/**
   * Asynchronously queries a Couchbase view and returns the result. The result can be accessed
   * row-wise via an iterator.
   *
   * @param view the view to run the query against.
   * @param query the type of query to run against the view.
   * @return a Future containing the results of the query.
   */
  private HttpFuture<ViewResponse> asyncQueryAndReduce(final View view, final Query query) {
    if (!view.hasReduce()) {
      throw new RuntimeException("This view doesn't contain a reduce function");
    }
    String uri = view.getURI() + query.toString();
    final CountDownLatch couchLatch = new CountDownLatch(1);
    final HttpFuture<ViewResponse> crv = new HttpFuture<ViewResponse>(couchLatch, 60000);

    final HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
    final HttpOperation op =
        new ReducedOperationImpl(
            request,
            new ViewCallback() {
              private ViewResponse vr = null;

              @Override
              public void receivedStatus(OperationStatus status) {
                crv.set(vr, status);
              }

              @Override
              public void complete() {
                couchLatch.countDown();
              }

              @Override
              public void gotData(ViewResponse response) {
                vr = response;
              }
            });
    crv.setOperation(op);
    addOp(op);
    return crv;
  }
  /**
   * Asynchronously queries a Couchbase view and returns the result. The result can be accessed
   * row-wise via an iterator. This type of query will return the view result but will not get the
   * documents associated with each row of the query.
   *
   * @param view the view to run the query against.
   * @param query the type of query to run against the view.
   * @return a Future containing the results of the query.
   */
  private HttpFuture<ViewResponse> asyncQueryAndExcludeDocs(View view, Query query) {
    String uri = view.getURI() + query.toString();
    final CountDownLatch couchLatch = new CountDownLatch(1);
    final HttpFuture<ViewResponse> crv = new HttpFuture<ViewResponse>(couchLatch, 60000);

    final HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
    final HttpOperation op =
        new NoDocsOperationImpl(
            request,
            new ViewCallback() {
              private ViewResponse vr = null;

              @Override
              public void receivedStatus(OperationStatus status) {
                crv.set(vr, status);
              }

              @Override
              public void complete() {
                couchLatch.countDown();
              }

              @Override
              public void gotData(ViewResponse response) {
                vr = response;
              }
            });
    crv.setOperation(op);
    addOp(op);
    return crv;
  }
  /**
   * Asynchronously queries a Couchbase view and returns the result. The result can be accessed
   * row-wise via an iterator. This type of query will return the view result along with all of the
   * documents for each row in the query.
   *
   * @param view the view to run the query against.
   * @param query the type of query to run against the view.
   * @return a Future containing the results of the query.
   */
  private HttpFuture<ViewResponse> asyncQueryAndIncludeDocs(View view, Query query) {
    assert view != null : "Who passed me a null view";
    assert query != null : "who passed me a null query";
    String viewUri = view.getURI();
    String queryToRun = query.toString();
    assert viewUri != null : "view URI seems to be null";
    assert queryToRun != null : "query seems to be null";
    String uri = viewUri + queryToRun;
    getLogger().info("lookin for:" + uri);
    final CountDownLatch couchLatch = new CountDownLatch(1);
    final ViewFuture crv = new ViewFuture(couchLatch, 60000);

    final HttpRequest request = new BasicHttpRequest("GET", uri, HttpVersion.HTTP_1_1);
    final HttpOperation op =
        new DocsOperationImpl(
            request,
            new ViewCallback() {
              private ViewResponse vr = null;

              @Override
              public void receivedStatus(OperationStatus status) {
                if (vr != null) {
                  Collection<String> ids = new LinkedList<String>();
                  Iterator<ViewRow> itr = vr.iterator();
                  while (itr.hasNext()) {
                    ids.add(itr.next().getId());
                  }
                  crv.set(vr, asyncGetBulk(ids), status);
                } else {
                  crv.set(null, null, status);
                }
              }

              @Override
              public void complete() {
                couchLatch.countDown();
              }

              @Override
              public void gotData(ViewResponse response) {
                vr = response;
              }
            });
    crv.setOperation(op);
    addOp(op);
    return crv;
  }