/**
   * make the hbase filter for selecting values of y-axis(response time) in order to select
   * transactions in scatter chart. 4 bytes for elapsed time should be attached for the prefix of
   * column qualifier for to use this filter.
   *
   * @param area
   * @param offsetTransactionId
   * @param offsetTransactionElapsed
   * @return
   */
  private Filter makeResponseTimeFilter(
      final SelectedScatterArea area,
      final TransactionId offsetTransactionId,
      int offsetTransactionElapsed) {
    // filter by response time
    ResponseTimeRange responseTimeRange = area.getResponseTimeRange();
    byte[] responseFrom = Bytes.toBytes(responseTimeRange.getFrom());
    byte[] responseTo = Bytes.toBytes(responseTimeRange.getTo());
    FilterList filterList = new FilterList(Operator.MUST_PASS_ALL);
    filterList.addFilter(
        new QualifierFilter(CompareOp.GREATER_OR_EQUAL, new BinaryPrefixComparator(responseFrom)));
    filterList.addFilter(
        new QualifierFilter(CompareOp.LESS_OR_EQUAL, new BinaryPrefixComparator(responseTo)));

    // add offset
    if (offsetTransactionId != null) {
      final Buffer buffer = new AutomaticBuffer(32);
      buffer.put(offsetTransactionElapsed);
      buffer.putPrefixedString(offsetTransactionId.getAgentId());
      buffer.putSVar(offsetTransactionId.getAgentStartTime());
      buffer.putVar(offsetTransactionId.getTransactionSequence());
      byte[] qualifierOffset = buffer.getBuffer();

      filterList.addFilter(
          new QualifierFilter(CompareOp.GREATER, new BinaryPrefixComparator(qualifierOffset)));
    }
    return filterList;
  }
  @Override
  public List<Dot> scanTraceScatter(
      String applicationName,
      SelectedScatterArea area,
      TransactionId offsetTransactionId,
      int offsetTransactionElapsed,
      int limit) {
    if (applicationName == null) {
      throw new NullPointerException("applicationName must not be null");
    }
    if (area == null) {
      throw new NullPointerException("range must not be null");
    }
    if (limit < 0) {
      throw new IllegalArgumentException("negative limit:" + limit);
    }
    logger.debug("scanTraceScatter");
    Scan scan = createScan(applicationName, area.getTimeRange());

    // method 1
    // not used yet. instead, use another row mapper (testing)
    // scan.setFilter(makeResponseTimeFilter(area, offsetTransactionId, offsetTransactionElapsed));

    // method 2
    ResponseTimeRange responseTimeRange = area.getResponseTimeRange();
    TraceIndexScatterMapper2 mapper =
        new TraceIndexScatterMapper2(responseTimeRange.getFrom(), responseTimeRange.getTo());

    List<List<Dot>> dotListList =
        hbaseOperations2.findParallel(
            HBaseTables.APPLICATION_TRACE_INDEX,
            scan,
            traceIdRowKeyDistributor,
            limit,
            mapper,
            APPLICATION_TRACE_INDEX_NUM_PARTITIONS);

    List<Dot> result = new ArrayList<>();
    for (List<Dot> dotList : dotListList) {
      result.addAll(dotList);
    }

    return result;
  }