/*
 * Copyright (C) 2008 The Guava Authors
 *
 * 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.common.collect.testing;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;

import com.google.common.annotations.GwtCompatible;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Stack;
import junit.framework.AssertionFailedError;

/**
 * Most of the logic for {@link IteratorTester} and {@link ListIteratorTester}.
 *
 * @param <E> the type of element returned by the iterator
 * @param <I> the type of the iterator ({@link Iterator} or {@link ListIterator})
 * @author Kevin Bourrillion
 * @author Chris Povirk
 */
@GwtCompatible
abstract class AbstractIteratorTester<E, I extends Iterator<E>> {
  private Stimulus<E, ? super I>[] stimuli;
  private final Iterator<E> elementsToInsert;
  private final Set<IteratorFeature> features;
  private final List<E> expectedElements;
  private final int startIndex;
  private final KnownOrder knownOrder;

  /**
   * Meta-exception thrown by {@link AbstractIteratorTester.MultiExceptionListIterator} instead of
   * throwing any particular exception type.
   */
  private abstract static class PermittedMetaException extends RuntimeException {
    static final PermittedMetaException UOE_OR_ISE =
        new PermittedMetaException("UnsupportedOperationException or IllegalStateException") {
          @Override
          boolean isPermitted(RuntimeException exception) {
            return exception instanceof UnsupportedOperationException
                || exception instanceof IllegalStateException;
          }
        };
    static final PermittedMetaException UOE =
        new PermittedMetaException("UnsupportedOperationException") {
          @Override
          boolean isPermitted(RuntimeException exception) {
            return exception instanceof UnsupportedOperationException;
          }
        };
    static final PermittedMetaException ISE =
        new PermittedMetaException("IllegalStateException") {
          @Override
          boolean isPermitted(RuntimeException exception) {
            return exception instanceof IllegalStateException;
          }
        };
    static final PermittedMetaException NSEE =
        new PermittedMetaException("NoSuchElementException") {
          @Override
          boolean isPermitted(RuntimeException exception) {
            return exception instanceof NoSuchElementException;
          }
        };

    private PermittedMetaException(String message) {
      super(message);
    }

    abstract boolean isPermitted(RuntimeException exception);

    void assertPermitted(RuntimeException exception) {
      if (!isPermitted(exception)) {
        String message =
            "Exception "
                + exception.getClass().getSimpleName()
                + " was thrown; expected "
                + getMessage();
        Helpers.fail(exception, message);
      }
    }

    private static final long serialVersionUID = 0;
  }

  private static final class UnknownElementException extends RuntimeException {
    private UnknownElementException(Collection<?> expected, Object actual) {
      super("Returned value '" + actual + "' not found. Remaining elements: " + expected);
    }

    private static final long serialVersionUID = 0;
  }

  /**
   * Quasi-implementation of {@link ListIterator} that works from a list of elements and a set of
   * features to support (from the enclosing {@link AbstractIteratorTester} instance). Instead of
   * throwing exceptions like {@link NoSuchElementException} at the appropriate times, it throws
   * {@link PermittedMetaException} instances, which wrap a set of all exceptions that the iterator
   * could throw during the invocation of that method. This is necessary because, e.g., a call to
   * {@code iterator().remove()} of an unmodifiable list could throw either {@link
   * IllegalStateException} or {@link UnsupportedOperationException}. Note that iterator
   * implementations should always throw one of the exceptions in a {@code PermittedExceptions}
   * instance, since {@code PermittedExceptions} is thrown only when a method call is invalid.
   *
   * <p>This class is accessible but not supported in GWT as it references {@link
   * PermittedMetaException}.
   */
  protected final class MultiExceptionListIterator implements ListIterator<E> {
    // TODO: track seen elements when order isn't guaranteed
    // TODO: verify contents afterward
    // TODO: something shiny and new instead of Stack
    // TODO: test whether null is supported (create a Feature)
    /**
     * The elements to be returned by future calls to {@code next()}, with the first at the top of
     * the stack.
     */
    final Stack<E> nextElements = new Stack<E>();
    /**
     * The elements to be returned by future calls to {@code previous()}, with the first at the top
     * of the stack.
     */
    final Stack<E> previousElements = new Stack<E>();
    /**
     * {@link #nextElements} if {@code next()} was called more recently then {@code previous},
     * {@link #previousElements} if the reverse is true, or -- overriding both of these -- {@code
     * null} if {@code remove()} or {@code add()} has been called more recently than either. We use
     * this to determine which stack to pop from on a call to {@code remove()} (or to pop from and
     * push to on a call to {@code set()}.
     */
    Stack<E> stackWithLastReturnedElementAtTop = null;

    MultiExceptionListIterator(List<E> expectedElements) {
      Helpers.addAll(nextElements, Helpers.reverse(expectedElements));
      for (int i = 0; i < startIndex; i++) {
        previousElements.push(nextElements.pop());
      }
    }

    @Override
    public void add(E e) {
      if (!features.contains(IteratorFeature.SUPPORTS_ADD)) {
        throw PermittedMetaException.UOE;
      }

      previousElements.push(e);
      stackWithLastReturnedElementAtTop = null;
    }

    @Override
    public boolean hasNext() {
      return !nextElements.isEmpty();
    }

    @Override
    public boolean hasPrevious() {
      return !previousElements.isEmpty();
    }

    @Override
    public E next() {
      return transferElement(nextElements, previousElements);
    }

    @Override
    public int nextIndex() {
      return previousElements.size();
    }

    @Override
    public E previous() {
      return transferElement(previousElements, nextElements);
    }

    @Override
    public int previousIndex() {
      return nextIndex() - 1;
    }

    @Override
    public void remove() {
      throwIfInvalid(IteratorFeature.SUPPORTS_REMOVE);

      stackWithLastReturnedElementAtTop.pop();
      stackWithLastReturnedElementAtTop = null;
    }

    @Override
    public void set(E e) {
      throwIfInvalid(IteratorFeature.SUPPORTS_SET);

      stackWithLastReturnedElementAtTop.pop();
      stackWithLastReturnedElementAtTop.push(e);
    }

    /**
     * Moves the given element from its current position in {@link #nextElements} to the top of the
     * stack so that it is returned by the next call to {@link Iterator#next()}. If the element is
     * not in {@link #nextElements}, this method throws an {@link UnknownElementException}.
     *
     * <p>This method is used when testing iterators without a known ordering. We poll the target
     * iterator's next element and pass it to the reference iterator through this method so it can
     * return the same element. This enables the assertion to pass and the reference iterator to
     * properly update its state.
     */
    void promoteToNext(E e) {
      if (nextElements.remove(e)) {
        nextElements.push(e);
      } else {
        throw new UnknownElementException(nextElements, e);
      }
    }

    private E transferElement(Stack<E> source, Stack<E> destination) {
      if (source.isEmpty()) {
        throw PermittedMetaException.NSEE;
      }

      destination.push(source.pop());
      stackWithLastReturnedElementAtTop = destination;
      return destination.peek();
    }

    private void throwIfInvalid(IteratorFeature methodFeature) {
      if (!features.contains(methodFeature)) {
        if (stackWithLastReturnedElementAtTop == null) {
          throw PermittedMetaException.UOE_OR_ISE;
        } else {
          throw PermittedMetaException.UOE;
        }
      } else if (stackWithLastReturnedElementAtTop == null) {
        throw PermittedMetaException.ISE;
      }
    }

    private List<E> getElements() {
      List<E> elements = new ArrayList<E>();
      Helpers.addAll(elements, previousElements);
      Helpers.addAll(elements, Helpers.reverse(nextElements));
      return elements;
    }
  }

  public enum KnownOrder {
    KNOWN_ORDER,
    UNKNOWN_ORDER
  }

  @SuppressWarnings("unchecked") // creating array of generic class Stimulus
  AbstractIteratorTester(
      int steps,
      Iterable<E> elementsToInsertIterable,
      Iterable<? extends IteratorFeature> features,
      Iterable<E> expectedElements,
      KnownOrder knownOrder,
      int startIndex) {
    // periodically we should manually try (steps * 3 / 2) here; all tests but
    // one should still pass (testVerifyGetsCalled()).
    stimuli = new Stimulus[steps];
    if (!elementsToInsertIterable.iterator().hasNext()) {
      throw new IllegalArgumentException();
    }
    elementsToInsert = Helpers.cycle(elementsToInsertIterable);
    this.features = Helpers.copyToSet(features);
    this.expectedElements = Helpers.copyToList(expectedElements);
    this.knownOrder = knownOrder;
    this.startIndex = startIndex;
  }

  /**
   * I'd like to make this a parameter to the constructor, but I can't because the stimulus
   * instances refer to {@code this}.
   */
  protected abstract Iterable<? extends Stimulus<E, ? super I>> getStimulusValues();

  /**
   * Returns a new target iterator each time it's called. This is the iterator you are trying to
   * test. This must return an Iterator that returns the expected elements passed to the constructor
   * in the given order. Warning: it is not enough to simply pull multiple iterators from the same
   * source Iterable, unless that Iterator is unmodifiable.
   */
  protected abstract I newTargetIterator();

  /**
   * Override this to verify anything after running a list of Stimuli.
   *
   * <p>For example, verify that calls to remove() actually removed the correct elements.
   *
   * @param elements the expected elements passed to the constructor, as mutated by {@code
   *     remove()}, {@code set()}, and {@code add()} calls
   */
  protected void verify(List<E> elements) {}

  /** Executes the test. */
  public final void test() {
    try {
      recurse(0);
    } catch (RuntimeException e) {
      throw new RuntimeException(Arrays.toString(stimuli), e);
    }
  }

  public void testForEachRemaining() {
    for (int i = 0; i < expectedElements.size() - 1; i++) {
      List<E> targetElements = new ArrayList<E>();
      Iterator<E> iterator = newTargetIterator();
      for (int j = 0; j < i; j++) {
        targetElements.add(iterator.next());
      }
      iterator.forEachRemaining(targetElements::add);
      if (knownOrder == KnownOrder.KNOWN_ORDER) {
        assertEquals(expectedElements, targetElements);
      } else {
        Helpers.assertEqualIgnoringOrder(expectedElements, targetElements);
      }
    }
  }

  private void recurse(int level) {
    // We're going to reuse the stimuli array 3^steps times by overwriting it
    // in a recursive loop.  Sneaky.
    if (level == stimuli.length) {
      // We've filled the array.
      compareResultsForThisListOfStimuli();
    } else {
      // Keep recursing to fill the array.
      for (Stimulus<E, ? super I> stimulus : getStimulusValues()) {
        stimuli[level] = stimulus;
        recurse(level + 1);
      }
    }
  }

  private void compareResultsForThisListOfStimuli() {
    int removes = Collections.frequency(Arrays.asList(stimuli), remove);
    if ((!features.contains(IteratorFeature.SUPPORTS_REMOVE) && removes > 1)
        || (stimuli.length >= 5 && removes > 2)) {
      // removes are the most expensive thing to test, since they often throw exceptions with stack
      // traces, so we test them a bit less aggressively
      return;
    }

    MultiExceptionListIterator reference = new MultiExceptionListIterator(expectedElements);
    I target = newTargetIterator();
    for (int i = 0; i < stimuli.length; i++) {
      try {
        stimuli[i].executeAndCompare(reference, target);
        verify(reference.getElements());
      } catch (AssertionFailedError cause) {
        Helpers.fail(cause, "failed with stimuli " + subListCopy(stimuli, i + 1));
      }
    }
  }

  private static List<Object> subListCopy(Object[] source, int size) {
    final Object[] copy = new Object[size];
    System.arraycopy(source, 0, copy, 0, size);
    return Arrays.asList(copy);
  }

  private interface IteratorOperation {
    Object execute(Iterator<?> iterator);
  }

  /**
   * Apply this method to both iterators and return normally only if both produce the same response.
   *
   * @see Stimulus#executeAndCompare(ListIterator, Iterator)
   */
  private <T extends Iterator<E>> void internalExecuteAndCompare(
      T reference, T target, IteratorOperation method) {
    Object referenceReturnValue = null;
    PermittedMetaException referenceException = null;
    Object targetReturnValue = null;
    RuntimeException targetException = null;

    try {
      targetReturnValue = method.execute(target);
    } catch (RuntimeException e) {
      targetException = e;
    }

    try {
      if (method == NEXT_METHOD
          && targetException == null
          && knownOrder == KnownOrder.UNKNOWN_ORDER) {
        /*
         * We already know the iterator is an Iterator<E>, and now we know that
         * we called next(), so the returned element must be of type E.
         */
        @SuppressWarnings("unchecked")
        E targetReturnValueFromNext = (E) targetReturnValue;
        /*
         * We have an Iterator<E> and want to cast it to
         * MultiExceptionListIterator. Because we're inside an
         * AbstractIteratorTester<E>, that's implicitly a cast to
         * AbstractIteratorTester<E>.MultiExceptionListIterator. The runtime
         * won't be able to verify the AbstractIteratorTester<E> part, so it's
         * an unchecked cast. We know, however, that the only possible value for
         * the type parameter is <E>, since otherwise the
         * MultiExceptionListIterator wouldn't be an Iterator<E>. The cast is
         * safe, even though javac can't tell.
         *
         * Sun bug 6665356 is an additional complication. Until OpenJDK 7, javac
         * doesn't recognize this kind of cast as unchecked cast. Neither does
         * Eclipse 3.4. Right now, this suppression is mostly unnecessary.
         */
        MultiExceptionListIterator multiExceptionListIterator =
            (MultiExceptionListIterator) reference;
        multiExceptionListIterator.promoteToNext(targetReturnValueFromNext);
      }

      referenceReturnValue = method.execute(reference);
    } catch (PermittedMetaException e) {
      referenceException = e;
    } catch (UnknownElementException e) {
      Helpers.fail(e, e.getMessage());
    }

    if (referenceException == null) {
      if (targetException != null) {
        Helpers.fail(targetException, "Target threw exception when reference did not");
      }

      /*
       * Reference iterator returned a value, so we should expect the
       * same value from the target
       */
      assertEquals(referenceReturnValue, targetReturnValue);

      return;
    }

    if (targetException == null) {
      fail("Target failed to throw " + referenceException);
    }

    /*
     * Reference iterator threw an exception, so we should expect an acceptable
     * exception from the target.
     */
    referenceException.assertPermitted(targetException);
  }

  private static final IteratorOperation REMOVE_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          iterator.remove();
          return null;
        }
      };

  private static final IteratorOperation NEXT_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          return iterator.next();
        }
      };

  private static final IteratorOperation PREVIOUS_METHOD =
      new IteratorOperation() {
        @Override
        public Object execute(Iterator<?> iterator) {
          return ((ListIterator<?>) iterator).previous();
        }
      };

  private final IteratorOperation newAddMethod() {
    final Object toInsert = elementsToInsert.next();
    return new IteratorOperation() {
      @Override
      public Object execute(Iterator<?> iterator) {
        @SuppressWarnings("unchecked")
        ListIterator<Object> rawIterator = (ListIterator<Object>) iterator;
        rawIterator.add(toInsert);
        return null;
      }
    };
  }

  private final IteratorOperation newSetMethod() {
    final E toInsert = elementsToInsert.next();
    return new IteratorOperation() {
      @Override
      public Object execute(Iterator<?> iterator) {
        @SuppressWarnings("unchecked")
        ListIterator<E> li = (ListIterator<E>) iterator;
        li.set(toInsert);
        return null;
      }
    };
  }

  abstract static class Stimulus<E, T extends Iterator<E>> {
    private final String toString;

    protected Stimulus(String toString) {
      this.toString = toString;
    }

    /**
     * Send this stimulus to both iterators and return normally only if both produce the same
     * response.
     */
    abstract void executeAndCompare(ListIterator<E> reference, T target);

    @Override
    public String toString() {
      return toString;
    }
  }

  Stimulus<E, Iterator<E>> hasNext =
      new Stimulus<E, Iterator<E>>("hasNext") {
        @Override
        void executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
          assertEquals(reference.hasNext(), target.hasNext());
        }
      };
  Stimulus<E, Iterator<E>> next =
      new Stimulus<E, Iterator<E>>("next") {
        @Override
        void executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
          internalExecuteAndCompare(reference, target, NEXT_METHOD);
        }
      };
  Stimulus<E, Iterator<E>> remove =
      new Stimulus<E, Iterator<E>>("remove") {
        @Override
        void executeAndCompare(ListIterator<E> reference, Iterator<E> target) {
          internalExecuteAndCompare(reference, target, REMOVE_METHOD);
        }
      };

  @SuppressWarnings("unchecked")
  List<Stimulus<E, Iterator<E>>> iteratorStimuli() {
    return Arrays.asList(hasNext, next, remove);
  }

  Stimulus<E, ListIterator<E>> hasPrevious =
      new Stimulus<E, ListIterator<E>>("hasPrevious") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          assertEquals(reference.hasPrevious(), target.hasPrevious());
        }
      };
  Stimulus<E, ListIterator<E>> nextIndex =
      new Stimulus<E, ListIterator<E>>("nextIndex") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          assertEquals(reference.nextIndex(), target.nextIndex());
        }
      };
  Stimulus<E, ListIterator<E>> previousIndex =
      new Stimulus<E, ListIterator<E>>("previousIndex") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          assertEquals(reference.previousIndex(), target.previousIndex());
        }
      };
  Stimulus<E, ListIterator<E>> previous =
      new Stimulus<E, ListIterator<E>>("previous") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          internalExecuteAndCompare(reference, target, PREVIOUS_METHOD);
        }
      };
  Stimulus<E, ListIterator<E>> add =
      new Stimulus<E, ListIterator<E>>("add") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          internalExecuteAndCompare(reference, target, newAddMethod());
        }
      };
  Stimulus<E, ListIterator<E>> set =
      new Stimulus<E, ListIterator<E>>("set") {
        @Override
        void executeAndCompare(ListIterator<E> reference, ListIterator<E> target) {
          internalExecuteAndCompare(reference, target, newSetMethod());
        }
      };

  @SuppressWarnings("unchecked")
  List<Stimulus<E, ListIterator<E>>> listIteratorStimuli() {
    return Arrays.asList(hasPrevious, nextIndex, previousIndex, previous, add, set);
  }
}
