// Copyright (C) 2010 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.server.query.change;

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

import com.google.common.base.Function;
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.common.collect.Lists;
import com.google.gerrit.server.query.AndPredicate;
import com.google.gerrit.server.query.Predicate;
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 extends AndPredicate<ChangeData>
    implements ChangeDataSource {
  private static final Comparator<Predicate<ChangeData>> CMP =
      new Comparator<Predicate<ChangeData>>() {
        @Override
        public int compare(Predicate<ChangeData> a, Predicate<ChangeData> b) {
          int ai = a instanceof ChangeDataSource ? 0 : 1;
          int bi = b instanceof ChangeDataSource ? 0 : 1;
          int cmp = ai - bi;

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

          if (cmp == 0 //
              && a instanceof ChangeDataSource //
              && b instanceof ChangeDataSource) {
            ChangeDataSource as = (ChangeDataSource) a;
            ChangeDataSource bs = (ChangeDataSource) b;
            cmp = as.getCardinality() - bs.getCardinality();

            if (cmp == 0) {
              cmp = (as.hasChange() ? 0 : 1)
                  - (bs.hasChange() ? 0 : 1);
            }
          }

          return cmp;
        }
      };

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

  private final int start;
  private int cardinality = -1;

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

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

  @Override
  public boolean hasChange() {
    ChangeDataSource source = source();
    return source != null && source.hasChange();
  }

  @Override
  public ResultSet<ChangeData> read() throws OrmException {
    try {
      return readImpl();
    } catch (OrmRuntimeException err) {
      Throwables.propagateIfInstanceOf(err.getCause(), OrmException.class);
      throw new OrmException(err);
    }
  }

  private ResultSet<ChangeData> readImpl() throws OrmException {
    ChangeDataSource source = source();
    if (source == null) {
      throw new OrmException("No ChangeDataSource: " + this);
    }
    List<ChangeData> r = Lists.newArrayList();
    ChangeData last = null;
    int nextStart = 0;
    boolean skipped = false;
    for (ChangeData data : buffer(source, source.read())) {
      if (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.
      //
      Paginated p = (Paginated) source;
      while (skipped && r.size() < p.getOptions().limit() + start) {
        skipped = false;
        ResultSet<ChangeData> next = p.restart(nextStart);

        for (ChangeData data : buffer(source, 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);
  }

  private Iterable<ChangeData> buffer(
      ChangeDataSource source,
      ResultSet<ChangeData> scanner) {
    final boolean loadChange = !source.hasChange();
    return FluentIterable
      .from(Iterables.partition(scanner, 50))
      .transformAndConcat(new Function<List<ChangeData>, List<ChangeData>>() {
        @Override
        public List<ChangeData> apply(List<ChangeData> buffer) {
          if (loadChange) {
            try {
              ChangeData.ensureChangeLoaded(buffer);
            } catch (OrmException e) {
              throw new OrmRuntimeException(e);
            }
          }
          return buffer;
        }
      });
  }

  private ChangeDataSource source() {
    int minCost = Integer.MAX_VALUE;
    Predicate<ChangeData> s = null;
    for (Predicate<ChangeData> p : getChildren()) {
      if (p instanceof ChangeDataSource && p.getCost() < minCost) {
        s = p;
        minCost = p.getCost();
      }
    }
    return (ChangeDataSource) s;
  }

  @Override
  public int getCardinality() {
    if (cardinality < 0) {
      cardinality = Integer.MAX_VALUE;
      for (Predicate<ChangeData> p : getChildren()) {
        if (p instanceof ChangeDataSource) {
          int c = ((ChangeDataSource) p).getCardinality();
          cardinality = Math.min(cardinality, c);
        }
      }
    }
    return cardinality;
  }
}
