// Copyright 2011 Google Inc. All Rights Reserved.

package com.google.gerrit.httpd;

import com.google.common.base.CharMatcher;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeDataSource;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.query.change.ChangeQueryRewriter;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashSet;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Singleton
class DirectChangeByCommit extends HttpServlet {
  private static final long serialVersionUID = 1L;
  private static final Logger log =
      LoggerFactory.getLogger(DirectChangeByCommit.class);

  private final ChangeQueryBuilder.Factory queryBuilder;
  private final Provider<ChangeQueryRewriter> queryRewriter;
  private final Provider<CurrentUser> currentUser;

  @Inject
  DirectChangeByCommit(ChangeQueryBuilder.Factory queryBuilder,
      Provider<ChangeQueryRewriter> queryRewriter,
      Provider<CurrentUser> currentUser) {
    this.queryBuilder = queryBuilder;
    this.queryRewriter = queryRewriter;
    this.currentUser = currentUser;
  }

  @Override
  protected void doGet(final HttpServletRequest req,
      final HttpServletResponse rsp) throws IOException {
    String query = CharMatcher.is('/').trimTrailingFrom(req.getPathInfo());
    HashSet<Change.Id> ids = new HashSet<>();
    try {
      ChangeQueryBuilder builder = queryBuilder.create(currentUser.get());
      Predicate<ChangeData> visibleToMe = builder.is_visible();
      Predicate<ChangeData> q = builder.parse(query);
      q = Predicate.and(q, builder.sortkey_before("z"), builder.limit(2), visibleToMe);

      ChangeQueryRewriter rewriter = queryRewriter.get();
      Predicate<ChangeData> s = rewriter.rewrite(q, 0);
      if (!(s instanceof ChangeDataSource)) {
        s = rewriter.rewrite(Predicate.and(builder.status_open(), q), 0);
      }

      if (s instanceof ChangeDataSource) {
        for (ChangeData d : ((ChangeDataSource) s).read()) {
          ids.add(d.getId());
        }
      }
    } catch (QueryParseException e) {
      log.info("Received invalid query by URL: /r/" + query);
    } catch (OrmException e) {
      log.warn("Cannot process query by URL: /r/" + query, e);
    }

    String token;
    if (ids.size() == 1) {
      // If exactly one change matches, link to that change.
      // TODO Link to a specific patch set, if one matched.
      token = PageLinks.toChange(ids.iterator().next());

    } else {
      // Otherwise, link to the query page.
      token = PageLinks.toChangeQuery(query);
    }
    UrlModule.toGerrit(token, req, rsp);
  }
}

@@ -144,233 +144,79 @@
 gle.
-gerrit.common.PageLinks;%0Aimport com.google.gerrit.reviewdb.client.Change;%0Aimport com.google.gerrit.server.CurrentUser;%0Aimport com.google.gerrit.server.query.Predicate;%0Aimport com.google.gerrit.server.query.QueryParseException
+common.collect.ImmutableList;%0Aimport com.google.gerrit.common.PageLinks
 ;%0Aim
@@ -242,38 +242,38 @@
 rit.
-server.query
+extensions.api
 .change
+s
 .Change
-Data
+s
 ;%0Aim
@@ -299,289 +299,180 @@
 rit.
-server.query.change.ChangeDataSource;%0Aimport com.google.gerrit.server.query.change.ChangeQueryBuilder;%0Aimport com.google.gerrit.server.query.change.ChangeQueryRewriter;%0Aimport com.google.gwtorm.server.OrmException;%0Aimport com.google.inject.Inject;%0Aimport com.google.inject.Provider
+extensions.common.ChangeInfo;%0Aimport com.google.gerrit.extensions.restapi.RestApiException;%0Aimport com.google.gerrit.reviewdb.client.Change;%0Aimport com.google.inject.Inject
 ;%0Aim
@@ -609,22 +609,19 @@
 va.util.
-HashSe
+Lis
 t;%0A%0Aimpo
@@ -982,436 +982,98 @@
 ange
-QueryBuilder.Factory queryBuilder;%0A  private final Provider%3CChangeQueryRewriter%3E queryRewriter;%0A  private final Provider%3CCurrentUser%3E currentUser;%0A%0A  @Inject%0A  DirectChangeByCommit(ChangeQueryBuilder.Factory queryBuilder,%0A      Provider%3CChangeQueryRewriter%3E queryRewriter,%0A      Provider%3CCurrentUser%3E currentUser) %7B%0A    this.queryBuilder = queryBuilder;%0A    this.queryRewriter = queryRewriter;%0A    this.currentUser = currentUser
+s changes;%0A%0A  @Inject%0A  DirectChangeByCommit(Changes changes) %7B%0A    this.changes = changes
 ;%0A  
@@ -1282,22 +1282,19 @@
     
-HashSe
+Lis
 t%3CChange
 .Id%3E
@@ -1293,839 +1293,110 @@
 ange
-.Id%3E ids = new HashSet%3C%3E();%0A    try %7B%0A      ChangeQueryBuilder builder = queryBuilder.create(currentUser.get());%0A      Predicate%3CChangeData%3E visibleToMe = builder.is_visible();%0A      Predicate%3CChangeData%3E q = builder.parse(query);%0A      q = Predicate.and(q, builder.sortkey_before(%22z%22), builder.limit(2), visibleToMe);%0A%0A      ChangeQueryRewriter rewriter = queryRewriter.get();%0A      Predicate%3CChangeData%3E s = rewriter.rewrite(q, 0);%0A      if (!(s instanceof ChangeDataSource)) %7B%0A        s = rewriter.rewrite(Predicate.and(builder.status_open(), q), 0);%0A      %7D%0A%0A      if (s instanceof ChangeDataSource) %7B%0A        for (ChangeData d : ((ChangeDataSource) s).read()) %7B%0A          ids.add(d.getId());%0A        %7D%0A      %7D%0A    %7D catch (QueryParseException e) %7B%0A      log.info(%22Received invalid query by URL: /r/%22 + query);%0A    %7D catch (Orm
+Info%3E results;%0A    try %7B%0A      results = changes.query(query).withLimit(2).get();%0A    %7D catch (RestApi
 Exce
@@ -1473,15 +1473,50 @@
 e);%0A
+      results = ImmutableList.of();%0A
     %7D%0A
-%0A
     
@@ -1537,18 +1537,22 @@
     if (
-id
+result
 s.size()
@@ -1714,18 +1714,47 @@
 oChange(
-id
+%0A          new Change.Id(result
 s.iterat
@@ -1764,20 +1764,28 @@
 ).next()
+._number)
 );%0A
-%0A
     %7D el

Use Changes query API