// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.index.query;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gwtorm.server.ListResultSet;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
import com.google.gwtorm.server.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class AndSource<T> extends AndPredicate<T>
    implements DataSource<T>, Comparator<Predicate<T>> {
  protected final DataSource<T> source;

  private final IsVisibleToPredicate<T> isVisibleToPredicate;
  private final int start;
  private final int cardinality;

  public AndSource(Collection<? extends Predicate<T>> that) {
    this(that, null, 0);
  }

  public AndSource(Predicate<T> that, IsVisibleToPredicate<T> isVisibleToPredicate) {
    this(that, isVisibleToPredicate, 0);
  }

  public AndSource(Predicate<T> that, IsVisibleToPredicate<T> isVisibleToPredicate, int start) {
    this(ImmutableList.of(that), isVisibleToPredicate, start);
  }

  public AndSource(
      Collection<? extends Predicate<T>> that,
      IsVisibleToPredicate<T> isVisibleToPredicate,
      int start) {
    super(that);
    checkArgument(start >= 0, "negative start: %s", start);
    this.isVisibleToPredicate = isVisibleToPredicate;
    this.start = start;

    int c = Integer.MAX_VALUE;
    DataSource<T> s = null;
    int minCost = Integer.MAX_VALUE;
    for (Predicate<T> p : sort(getChildren())) {
      if (p instanceof DataSource) {
        c = Math.min(c, ((DataSource<?>) p).getCardinality());

        int cost = p.estimateCost();
        if (cost < minCost) {
          s = toDataSource(p);
          minCost = cost;
        }
      }
    }
    this.source = s;
    this.cardinality = c;
  }

  @Override
  public ResultSet<T> read() throws OrmException {
    try {
      return readImpl();
    } catch (OrmRuntimeException err) {
      if (err.getCause() != null) {
        Throwables.throwIfInstanceOf(err.getCause(), OrmException.class);
      }
      throw new OrmException(err);
    }
  }

  private ResultSet<T> readImpl() throws OrmException {
    if (source == null) {
      throw new OrmException("No DataSource: " + this);
    }
    List<T> r = new ArrayList<>();
    T last = null;
    int nextStart = 0;
    boolean skipped = false;
    for (T data : buffer(source.read())) {
      if (!isMatchable() || match(data)) {
        r.add(data);
      } else {
        skipped = true;
      }
      last = data;
      nextStart++;
    }

    if (skipped && last != null && source instanceof Paginated) {
      // If our source is a paginated source and we skipped at
      // least one of its results, we may not have filled the full
      // limit the caller wants.  Restart the source and continue.
      //
      @SuppressWarnings("unchecked")
      Paginated<T> p = (Paginated<T>) source;
      while (skipped && r.size() < p.getOptions().limit() + start) {
        skipped = false;
        ResultSet<T> next = p.restart(nextStart);

        for (T data : buffer(next)) {
          if (match(data)) {
            r.add(data);
          } else {
            skipped = true;
          }
          nextStart++;
        }
      }
    }

    if (start >= r.size()) {
      r = ImmutableList.of();
    } else if (start > 0) {
      r = ImmutableList.copyOf(r.subList(start, r.size()));
    }
    return new ListResultSet<>(r);
  }

  @Override
  public boolean isMatchable() {
    return isVisibleToPredicate != null || super.isMatchable();
  }

  @Override
  public boolean match(T object) throws OrmException {
    if (isVisibleToPredicate != null && !isVisibleToPredicate.match(object)) {
      return false;
    }

    if (super.isMatchable() && !super.match(object)) {
      return false;
    }

    return true;
  }

  private Iterable<T> buffer(ResultSet<T> scanner) {
    return FluentIterable.from(Iterables.partition(scanner, 50))
        .transformAndConcat(this::transformBuffer);
  }

  protected List<T> transformBuffer(List<T> buffer) throws OrmRuntimeException {
    return buffer;
  }

  @Override
  public int getCardinality() {
    return cardinality;
  }

  private List<Predicate<T>> sort(Collection<? extends Predicate<T>> that) {
    List<Predicate<T>> r = new ArrayList<>(that);
    Collections.sort(r, this);
    return r;
  }

  @Override
  public int compare(Predicate<T> a, Predicate<T> b) {
    int ai = a instanceof DataSource ? 0 : 1;
    int bi = b instanceof DataSource ? 0 : 1;
    int cmp = ai - bi;

    if (cmp == 0) {
      cmp = a.estimateCost() - b.estimateCost();
    }

    if (cmp == 0 && a instanceof DataSource && b instanceof DataSource) {
      DataSource<?> as = (DataSource<?>) a;
      DataSource<?> bs = (DataSource<?>) b;
      cmp = as.getCardinality() - bs.getCardinality();
    }
    return cmp;
  }

  @SuppressWarnings("unchecked")
  private DataSource<T> toDataSource(Predicate<T> pred) {
    return (DataSource<T>) pred;
  }
}
