ProductSummary.java

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

import gov.usgs.earthquake.product.Product;
import gov.usgs.earthquake.product.ProductId;
import gov.usgs.util.XmlUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.math.BigDecimal;
import java.util.List;
import java.net.URI;

/**
 * A ProductSummary is essentially a product without its contents.
 *
 * These are usually created by {@link IndexerModule}s, which may inspect
 * Product Content to add additional summary properties.
 */
public class ProductSummary {

  /** An ID used by the ProductIndex. */
  private Long indexId = null;

  /** The product id. */
  private ProductId id = null;

  /** The product status. */
  private String status = null;

  /** The product properties. */
  private Map<String, String> properties = new HashMap<String, String>();

  /** The product links. */
  private Map<String, List<URI>> links = new HashMap<String, List<URI>>();

  /** Unique identifier for this event. */
  private String eventSource = null;

  /** Unique identifier from the event network. */
  private String eventSourceCode = null;

  /** When the event occurred. */
  private Date eventTime = null;

  /** Where the event occurred. */
  private BigDecimal eventLatitude = null;

  /** Where the event occurred. */
  private BigDecimal eventLongitude = null;

  /** Where the event occurred. */
  private BigDecimal eventDepth = null;

  /** How big the event was. */
  private BigDecimal eventMagnitude = null;

  /** Product version. */
  private String version = null;

  /** Whether this product is "preferred". */
  private long preferredWeight = 0;

  /**
   * Empty constructor.
   */
  public ProductSummary() {
  }

  /**
   * Copy constructor for ProductSummary.
   *
   * Does a deep copy of properties and links maps. All other attributes are
   * copied by reference.
   *
   * @param copy product summary to copy.
   */
  public ProductSummary(final ProductSummary copy) {
    this.indexId = copy.getIndexId();
    this.id = copy.getId();
    this.status = copy.getStatus();
    this.properties.putAll(copy.getProperties());

    Map<String, List<URI>> copyLinks = copy.getLinks();
    Iterator<String> iter = copyLinks.keySet().iterator();
    while (iter.hasNext()) {
      String relation = iter.next();
      links.put(relation, new LinkedList<URI>(copyLinks.get(relation)));
    }

    this.setEventSource(copy.getEventSource());
    this.setEventSourceCode(copy.getEventSourceCode());
    this.setEventTime(copy.getEventTime());
    this.setEventLatitude(copy.getEventLatitude());
    this.setEventLongitude(copy.getEventLongitude());
    this.setEventDepth(copy.getEventDepth());
    this.setEventMagnitude(copy.getEventMagnitude());
    this.setVersion(copy.getVersion());
    this.setPreferredWeight(copy.getPreferredWeight());
  }

  /**
   * Create a ProductSummary from a product.
   *
   * All attributes are copied from the product, and preferredWeight is set to 1L.
   *
   * @param product the product to summarize.
   */
  public ProductSummary(final Product product) {
    this.id = product.getId();
    this.status = product.getStatus();
    this.properties.putAll(product.getProperties());

    Map<String, List<URI>> copyLinks = product.getLinks();
    Iterator<String> iter = copyLinks.keySet().iterator();
    while (iter.hasNext()) {
      String relation = iter.next();
      links.put(relation, new LinkedList<URI>(copyLinks.get(relation)));
    }

    this.setEventSource(product.getEventSource());
    this.setEventSourceCode(product.getEventSourceCode());
    this.setEventTime(product.getEventTime());
    this.setEventLatitude(product.getLatitude());
    this.setEventLongitude(product.getLongitude());
    this.setEventDepth(product.getDepth());
    this.setEventMagnitude(product.getMagnitude());
    this.setVersion(product.getVersion());
    this.setPreferredWeight(1L);
  }

  /** @return indexId */
  public Long getIndexId() {
    return indexId;
  }

  /** @param indexId to set */
  public void setIndexId(Long indexId) {
    this.indexId = indexId;
  }

  /** @return product id */
  public ProductId getId() {
    return id;
  }

  /** @param id to set */
  public void setId(ProductId id) {
    this.id = id;
  }

  /** @return status */
  public String getStatus() {
    return status;
  }

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

  /** @return if product is deleted */
  public boolean isDeleted() {
    if (Product.STATUS_DELETE.equalsIgnoreCase(this.status)) {
      return true;
    } else {
      return false;
    }
  }

  /** @return preferredWeight */
  public long getPreferredWeight() {
    return preferredWeight;
  }

  /** @param weight to set */
  public void setPreferredWeight(long weight) {
    this.preferredWeight = weight;
  }

  /**
   * @return the properties
   */
  public Map<String, String> getProperties() {
    return properties;
  }

  /**
   * @param properties the properties to set
   */
  public void setProperties(final Map<String, String> properties) {
    this.properties.putAll(properties);
  }

  /**
   * Returns a reference to the links map.
   *
   * @return the links
   */
  public Map<String, List<URI>> getLinks() {
    return links;
  }

  /**
   * Copies entries from provided map.
   *
   * @param links the links to set
   */
  public void setLinks(final Map<String, List<URI>> links) {
    this.links.clear();
    this.links.putAll(links);
  }

  /**
   * Add a link to a product.
   *
   * @param relation how link is related to product.
   * @param href     actual link.
   */
  public void addLink(final String relation, final URI href) {
    List<URI> relationLinks = links.get(relation);
    if (relationLinks == null) {
      relationLinks = new LinkedList<URI>();
      links.put(relation, relationLinks);
    }
    relationLinks.add(href);
  }

  /** @return null or eventId */
  public String getEventId() {
    if (eventSource == null || eventSourceCode == null) {
      return null;
    }
    return (eventSource + eventSourceCode).toLowerCase();
  }

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

  /** @param eventSource to set */
  public void setEventSource(String eventSource) {
    this.eventSource = eventSource;

    // event ids are case insensitive, force lower.
    if (this.eventSource != null) {
      this.eventSource = this.eventSource.toLowerCase();
    }

    if (this.eventSource != null) {
      this.properties.put(Product.EVENTSOURCE_PROPERTY, this.eventSource);
    } else {
      this.properties.remove(Product.EVENTSOURCE_PROPERTY);
    }
  }

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

  /** @param eventSourceCode to set */
  public void setEventSourceCode(String eventSourceCode) {
    this.eventSourceCode = eventSourceCode;

    // event ids are case insensitive, force lower.
    if (this.eventSourceCode != null) {
      this.eventSourceCode = this.eventSourceCode.toLowerCase();
    }

    if (this.eventSourceCode != null) {
      this.properties.put(Product.EVENTSOURCECODE_PROPERTY, this.eventSourceCode);
    } else {
      this.properties.remove(Product.EVENTSOURCECODE_PROPERTY);
    }
  }

  /** @return eventTime */
  public Date getEventTime() {
    return eventTime;
  }

  /** @param eventTime to set */
  public void setEventTime(Date eventTime) {
    this.eventTime = eventTime;
    if (eventTime != null) {
      this.properties.put(Product.EVENTTIME_PROPERTY, XmlUtils.formatDate(eventTime));
    } else {
      this.properties.remove(Product.EVENTTIME_PROPERTY);
    }

  }

  /** @return eventLatitude */
  public BigDecimal getEventLatitude() {
    return eventLatitude;
  }

  /** @param eventLatitude to set */
  public void setEventLatitude(BigDecimal eventLatitude) {
    this.eventLatitude = eventLatitude;
    if (eventLatitude != null) {
      this.properties.put(Product.LATITUDE_PROPERTY, eventLatitude.toString());
    } else {
      this.properties.remove(Product.LATITUDE_PROPERTY);
    }
  }

  /** @return eventLongitude */
  public BigDecimal getEventLongitude() {
    return eventLongitude;
  }

  /** @param eventLongitude to set */
  public void setEventLongitude(BigDecimal eventLongitude) {
    this.eventLongitude = eventLongitude;
    if (eventLongitude != null) {
      this.properties.put(Product.LONGITUDE_PROPERTY, eventLongitude.toString());
    } else {
      this.properties.remove(Product.LONGITUDE_PROPERTY);
    }
  }

  /** @return eventDepth */
  public BigDecimal getEventDepth() {
    return eventDepth;
  }

  /** @param eventDepth to set */
  public void setEventDepth(BigDecimal eventDepth) {
    this.eventDepth = eventDepth;
    if (eventDepth != null) {
      this.properties.put(Product.DEPTH_PROPERTY, eventDepth.toString());
    } else {
      this.properties.remove(Product.DEPTH_PROPERTY);
    }
  }

  /** @return eventMagnitude */
  public BigDecimal getEventMagnitude() {
    return eventMagnitude;
  }

  /** @param eventMagnitude to set */
  public void setEventMagnitude(BigDecimal eventMagnitude) {
    this.eventMagnitude = eventMagnitude;
    if (eventMagnitude != null) {
      this.properties.put(Product.MAGNITUDE_PROPERTY, eventMagnitude.toString());
    } else {
      this.properties.remove(Product.MAGNITUDE_PROPERTY);
    }
  }

  /** @return version */
  public String getVersion() {
    return version;
  }

  /** @param version to set */
  public void setVersion(String version) {
    this.version = version;
    if (version != null) {
      this.properties.put(Product.VERSION_PROPERTY, version);
    } else {
      this.properties.remove(Product.VERSION_PROPERTY);
    }
  }

  /** @return type */
  public String getType() {
    return getId().getType();
  }

  /** @return source */
  public String getSource() {
    return getId().getSource();
  }

  /** @return code */
  public String getCode() {
    return getId().getCode();
  }

  /** @return updateTime */
  public Date getUpdateTime() {
    return getId().getUpdateTime();
  }

  /**
   * Compares two ProductSummaries to determine if they are equal.
   *
   * This first implementation just considers the ProductId of each summary. This
   * is probably not the best way to check for equality.
   */
  @Override
  public boolean equals(Object o) {
    if (o instanceof ProductSummary) {
      return ((ProductSummary) o).getId().equals(this.getId());
    }
    return false;
  }

  /**
   * Generate hashcode for ProductId using all components.
   *
   * This implementation just uses hashcode from ProductId.
   */
  @Override
  public int hashCode() {
    return getId().hashCode();
  }

}