ProductIndexQuery.java

/*
 * ProductIndexQuery
 */
package gov.usgs.earthquake.indexer;

import gov.usgs.earthquake.product.ProductId;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Criteria for finding events.
 *
 * All properties are inclusive. When a property is null, it means any value.
 *
 * Expected combinations:
 *
 * 1) find events based on event parameters event time event latitude event
 * longitude
 *
 * 2) find previously received update of product product source product type
 * product code
 *
 * 3) find related products/events product ids
 *
 * 4) find related products/events event ids
 */
public class ProductIndexQuery implements Comparable<ProductIndexQuery> {

  /**
   * Event search types determine whether to search only preferred event
   * attributes (faster), or all event attributes from any associated product
   * (more complete).
   */
  private static enum EventSearchTypes {
    /**
     * Search preferred event attributes.
     *
     * NOTE: SEARCH_EVENT_PREFERRED should ONLY be used on event queries. Using this
     * on product queries will more than likely break.
     */
    SEARCH_EVENT_PREFERRED,

    /** Search event product attributes. */
    SEARCH_EVENT_PRODUCTS
  };

  /**
   * Result types determine which products associated to an event are returned.
   */
  private static enum ResultTypes {
    /** Only include current versions of products in the result. */
    RESULT_TYPE_CURRENT,

    /** Only include superseded (old) versions of products in the result. */

    RESULT_TYPE_SUPERSEDED,

    /**
     * Include both current and superseded versions of products in the result.
     */
    RESULT_TYPE_ALL;
  };

  /** EventSearchType for SEARCH_EVENT_PREFERRED */
  public static EventSearchTypes SEARCH_EVENT_PREFERRED = EventSearchTypes.SEARCH_EVENT_PREFERRED;
  /** EventSearchType for SEARCH_EVENT_PRODCUTS */
  public static EventSearchTypes SEARCH_EVENT_PRODUCTS = EventSearchTypes.SEARCH_EVENT_PRODUCTS;

  /** ResultType for RESULT_TYPE_CURRENT */
  public static ResultTypes RESULT_TYPE_CURRENT = ResultTypes.RESULT_TYPE_CURRENT;
  /** ResultType for RESULT_TYPE_SUPERSEDED */
  public static ResultTypes RESULT_TYPE_SUPERSEDED = ResultTypes.RESULT_TYPE_SUPERSEDED;
  /** ResultType for RESULT_TYPE_ALL */
  public static ResultTypes RESULT_TYPE_ALL = ResultTypes.RESULT_TYPE_ALL;

  /** Search preferred or all event attributes? */
  private EventSearchTypes eventSearchType = SEARCH_EVENT_PRODUCTS;

  /** Include previous versions? */
  private ResultTypes resultType = RESULT_TYPE_CURRENT;

  /** Event source */
  private String eventSource;

  /** Event source code */
  private String eventSourceCode;

  /** Minimum event time, inclusive. */
  private Date minEventTime;

  /** Maximum event time, inclusive. */
  private Date maxEventTime;

  /** Minimum event latitude. */
  private BigDecimal minEventLatitude;

  /** Maximum event latitude. */
  private BigDecimal maxEventLatitude;

  /** Minimum event longitude. */
  private BigDecimal minEventLongitude;

  /** Maximum event longitude. */
  private BigDecimal maxEventLongitude;

  /** Minimum event depth. */
  private BigDecimal minEventDepth;

  /** Maximum event depth. */
  private BigDecimal maxEventDepth;

  /** Minimum event magnitude. */
  private BigDecimal minEventMagnitude;

  /** Maximum event magnitude. */
  private BigDecimal maxEventMagnitude;

  /** A list of product ids to search. */
  private List<ProductId> productIds = new LinkedList<ProductId>();

  /** Minimum product update time. */
  private Date minProductUpdateTime;

  /** Maximum product update time. */
  private Date maxProductUpdateTime;

  /** The product source. */
  private String productSource;

  /** The product type. */
  private String productType;

  /** The product code. */
  private String productCode;

  /** The product version */
  private String productVersion;

  /** The product status */
  private String productStatus;

  /** The product index ID; unique per productIndex */
  private Long minProductIndexId;

  /** The max number of results */
  private Integer limit;

  /** List of columns to order by */
  private String orderBy;

  /**
   * Construct a new ProductIndexQuery.
   */
  public ProductIndexQuery() {
  }

  /** @param eventSearchType to set */
  public void setEventSearchType(EventSearchTypes eventSearchType) {
    this.eventSearchType = eventSearchType;
  }

  /** @return eventSearchType */
  public EventSearchTypes getEventSearchType() {
    return eventSearchType;
  }

  /** @param resultType to set */
  public void setResultType(ResultTypes resultType) {
    this.resultType = resultType;
  }

  /** @return resultType */
  public ResultTypes getResultType() {
    return resultType;
  }

  /** @param eventSource to set */
  public void setEventSource(String eventSource) {
    this.eventSource = (eventSource == null ? null : eventSource.toLowerCase());
  }

  /** @return eventSource */
  public String getEventSource() {
    return eventSource;
  }

  /** @param eventSourceCode to set */
  public void setEventSourceCode(String eventSourceCode) {
    this.eventSourceCode = (eventSourceCode == null ? null : eventSourceCode.toLowerCase());
  }

  /** @return eventSourceCode */
  public String getEventSourceCode() {
    return eventSourceCode;
  }

  /** @return minEventTime */
  public Date getMinEventTime() {
    return minEventTime;
  }

  /** @param minEventTime to set */
  public void setMinEventTime(Date minEventTime) {
    this.minEventTime = minEventTime;
  }

  /** @return maxEventTime */
  public Date getMaxEventTime() {
    return maxEventTime;
  }

  /** @param maxEventTime to set */
  public void setMaxEventTime(Date maxEventTime) {
    this.maxEventTime = maxEventTime;
  }

  /** @return minEventLatitude */
  public BigDecimal getMinEventLatitude() {
    return minEventLatitude;
  }

  /** @param minEventLatitude to set */
  public void setMinEventLatitude(BigDecimal minEventLatitude) {
    this.minEventLatitude = minEventLatitude;
  }

  /** @return maxEventLatitude */
  public BigDecimal getMaxEventLatitude() {
    return maxEventLatitude;
  }

  /** @param maxEventLatitude to set */
  public void setMaxEventLatitude(BigDecimal maxEventLatitude) {
    this.maxEventLatitude = maxEventLatitude;
  }

  /** @return minEventLongitude */
  public BigDecimal getMinEventLongitude() {
    return minEventLongitude;
  }

  /** @param minEventLongitude to set */
  public void setMinEventLongitude(BigDecimal minEventLongitude) {
    this.minEventLongitude = minEventLongitude;
  }

  /** @return maxEventLongitude */
  public BigDecimal getMaxEventLongitude() {
    return maxEventLongitude;
  }

  /** @param maxEventLongitude to set */
  public void setMaxEventLongitude(BigDecimal maxEventLongitude) {
    this.maxEventLongitude = maxEventLongitude;
  }

  /** @return minEventDepth */
  public BigDecimal getMinEventDepth() {
    return minEventDepth;
  }

  /** @param minEventDepth to set */
  public void setMinEventDepth(BigDecimal minEventDepth) {
    this.minEventDepth = minEventDepth;
  }

  /** @return maxEventDepth */
  public BigDecimal getMaxEventDepth() {
    return maxEventDepth;
  }

  /** @param maxEventDepth to set */
  public void setMaxEventDepth(BigDecimal maxEventDepth) {
    this.maxEventDepth = maxEventDepth;
  }

  /** @return minEventMagnitude */
  public BigDecimal getMinEventMagnitude() {
    return minEventMagnitude;
  }

  /** @param minEventMagnitude to set */
  public void setMinEventMagnitude(BigDecimal minEventMagnitude) {
    this.minEventMagnitude = minEventMagnitude;
  }

  /** @return maxEventMagnitude */
  public BigDecimal getMaxEventMagnitude() {
    return maxEventMagnitude;
  }

  /** @param maxEventMagnitude to set */
  public void setMaxEventMagnitude(BigDecimal maxEventMagnitude) {
    this.maxEventMagnitude = maxEventMagnitude;
  }

  /** @return list of product Ids */
  public List<ProductId> getProductIds() {
    return productIds;
  }

  /** @param productIds list to set */
  public void setProductIds(List<ProductId> productIds) {
    this.productIds.clear();
    this.productIds.addAll(productIds);
  }

  /** @return minProductUpdateTime */
  public Date getMinProductUpdateTime() {
    return minProductUpdateTime;
  }

  /** @param minProductUpdateTime to set */
  public void setMinProductUpdateTime(Date minProductUpdateTime) {
    this.minProductUpdateTime = minProductUpdateTime;
  }

  /** @return maxProductUpdateTime */
  public Date getMaxProductUpdateTime() {
    return maxProductUpdateTime;
  }

  /** @param maxProductUpdateTime to set */
  public void setMaxProductUpdateTime(Date maxProductUpdateTime) {
    this.maxProductUpdateTime = maxProductUpdateTime;
  }

  /** @return productSource */
  public String getProductSource() {
    return productSource;
  }

  /** @param productSource to set */
  public void setProductSource(String productSource) {
    this.productSource = productSource;
  }

  /** @return productType */
  public String getProductType() {
    return productType;
  }

  /** @param productType to set */
  public void setProductType(String productType) {
    this.productType = productType;
  }

  /** @return productCode */
  public String getProductCode() {
    return productCode;
  }

  /** @param productCode to set */
  public void setProductCode(String productCode) {
    this.productCode = productCode;
  }

  /** @param productVersion to set */
  public void setProductVersion(String productVersion) {
    this.productVersion = productVersion;
  }

  /** @return productVersion */
  public String getProductVersion() {
    return productVersion;
  }

  /** @param productStatus to set */
  public void setProductStatus(String productStatus) {
    this.productStatus = productStatus;
  }

  /** @return productStatus */
  public String getProductStatus() {
    return productStatus;
  }

  /** @param minProductIndexId to set */
  public void setMinProductIndexId(final Long minProductIndexId) {
    this.minProductIndexId = minProductIndexId;
  }

  /** @return minProductIndexId */
  public Long getMinProductIndexId() {
    return this.minProductIndexId;
  }

  /** @param limit to set */
  public void setLimit(final Integer limit) {
    this.limit = limit;
  }

  /** @return limit */
  public Integer getLimit() {
    return this.limit;
  }

  /** @param orderBy to set */
  public void setOrderBy(final String orderBy) {
    this.orderBy = orderBy;
  }

  /** @return orderBy */
  public String getOrderBy() {
    return this.orderBy;
  }

  @Override
  public boolean equals(Object that) {
    return (this.compareTo((ProductIndexQuery) that)) == 0;
  }

  @Override
  public int compareTo(ProductIndexQuery that) {
    int r = 0;

    if ((r = compare(this.eventSource, that.eventSource)) != 0) {
      return r;
    }
    if ((r = compare(this.eventSourceCode, that.eventSourceCode)) != 0) {
      return r;
    }
    if ((r = compare(this.maxEventDepth, that.maxEventDepth)) != 0) {
      return r;
    }
    if ((r = compare(this.maxEventLatitude, that.maxEventLatitude)) != 0) {
      return r;
    }
    if ((r = compare(this.maxEventLongitude, that.maxEventLongitude)) != 0) {
      return r;
    }
    if ((r = compare(this.maxEventMagnitude, that.maxEventMagnitude)) != 0) {
      return r;
    }
    if ((r = compare(this.maxEventTime, that.maxEventTime)) != 0) {
      return r;
    }
    if ((r = compare(this.maxProductUpdateTime, that.maxProductUpdateTime)) != 0) {
      return r;
    }

    if ((r = compare(this.minEventDepth, that.minEventDepth)) != 0) {
      return r;
    }
    if ((r = compare(this.minEventLatitude, that.minEventLatitude)) != 0) {
      return r;
    }
    if ((r = compare(this.minEventLongitude, that.minEventLongitude)) != 0) {
      return r;
    }
    if ((r = compare(this.minEventMagnitude, that.minEventMagnitude)) != 0) {
      return r;
    }
    if ((r = compare(this.minEventTime, that.minEventTime)) != 0) {
      return r;
    }
    if ((r = compare(this.minProductUpdateTime, that.minProductUpdateTime)) != 0) {
      return r;
    }

    if ((r = compare(this.productCode, that.productCode)) != 0) {
      return r;
    }
    if ((r = compare(this.productSource, that.productSource)) != 0) {
      return r;
    }
    if ((r = compare(this.productStatus, that.productStatus)) != 0) {
      return r;
    }
    if ((r = compare(this.productType, that.productType)) != 0) {
      return r;
    }
    if ((r = compare(this.productVersion, that.productVersion)) != 0) {
      return r;
    }

    if ((r = (that.productIds.size() - this.productIds.size())) != 0) {
      // different size lists
      return r;
    } else {
      // lists are same size, check contents
      Iterator<ProductId> thisIter = this.productIds.iterator();
      Iterator<ProductId> thatIter = that.productIds.iterator();
      while (thisIter.hasNext() && thatIter.hasNext()) {
        r = thisIter.next().compareTo(thatIter.next());
        if (r != 0) {
          return r;
        }
      }
    }

    return 0;
  }

  /**
   * Compare function
   *
   * @param <T> Type
   * @param o1  First item to compare
   * @param o2  Second to comoare
   * @return 0 if equal, 1 if o1 is null, -1 if o2 null, or the comparison
   */
  protected <T extends Comparable<T>> int compare(T o1, T o2) {
    if (o1 == null && o2 == null) {
      return 0;
    } else if (o1 == null && o2 != null) {
      return 1;
    } else if (o1 != null && o2 == null) {
      return -1;
    } else {
      return o1.compareTo(o2);
    }
  }

  /**
   * Log function
   *
   * @param logger logger object
   */
  public void log(final Logger logger) {
    if (!logger.isLoggable(Level.FINEST)) {
      return;
    }
    StringBuffer buf = new StringBuffer("Product Index Query");
    buf.append("\neventSearchType=").append(this.eventSearchType);
    buf.append("\nresultType=").append(this.resultType);
    if (this.eventSource != null) {
      buf.append("\neventSource=").append(this.eventSource);
    }
    if (this.eventSourceCode != null) {
      buf.append("\neventSourceCode=").append(this.eventSourceCode);
    }
    if (this.minEventTime != null) {
      buf.append("\nminEventTime=").append(this.minEventTime);
    }
    if (this.maxEventTime != null) {
      buf.append("\nmaxEventTime=").append(this.maxEventTime);
    }
    if (this.minEventLatitude != null) {
      buf.append("\nminEventLatitude=").append(this.minEventLatitude);
    }
    if (this.maxEventLatitude != null) {
      buf.append("\nmaxEventLatitude=").append(this.maxEventLatitude);
    }
    if (this.minEventLongitude != null) {
      buf.append("\nminEventLongitude=").append(this.minEventLongitude);
    }
    if (this.maxEventLongitude != null) {
      buf.append("\nmaxEventLongitude=").append(this.maxEventLongitude);
    }
    if (this.minEventDepth != null) {
      buf.append("\nminEventDepth=").append(this.minEventDepth);
    }
    if (this.maxEventDepth != null) {
      buf.append("\nmaxEventDepth=").append(this.maxEventDepth);
    }
    if (this.minEventMagnitude != null) {
      buf.append("\nminEventMagnitude=").append(this.minEventMagnitude);
    }
    if (this.maxEventMagnitude != null) {
      buf.append("\nmaxEventMagnitude=").append(this.maxEventMagnitude);
    }
    if (this.productIds.size() > 0) {
      buf.append("\nproduct ids=");
      Iterator<ProductId> iter = this.productIds.iterator();
      while (iter.hasNext()) {
        buf.append(iter.next().toString()).append(" ");
      }
    }
    if (this.minProductUpdateTime != null) {
      buf.append("\nminProductUpdateTime=").append(this.minProductUpdateTime);
    }
    if (this.maxProductUpdateTime != null) {
      buf.append("\nmaxProductUpdateTime=").append(this.maxProductUpdateTime);
    }
    if (this.productSource != null) {
      buf.append("\nproductSource=").append(this.productSource);
    }
    if (this.productType != null) {
      buf.append("\nproductType=").append(this.productType);
    }
    if (this.productCode != null) {
      buf.append("\nproductCode=").append(this.productCode);
    }
    if (this.productVersion != null) {
      buf.append("\nproductVersion=").append(this.productVersion);
    }
    if (this.productStatus != null) {
      buf.append("\nproductStatus=").append(this.productStatus);
    }

    logger.finest(buf.toString());
  }
}