/*
 * Copyright 2017 HugeGraph Authors
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. The ASF
 * licenses this file to You 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 org.apache.hugegraph.unit.iterator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.junit.Test;

import org.apache.hugegraph.iterator.ListIterator;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.unit.BaseUnitTest;
import org.apache.hugegraph.unit.iterator.ExtendableIteratorTest.CloseableItor;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;

@SuppressWarnings("resource")
public class ListIteratorTest extends BaseUnitTest {

    private static final Iterator<Integer> EMPTY = Collections.emptyIterator();

    private static final List<Integer> DATA1 = ImmutableList.of(1);
    private static final List<Integer> DATA2 = ImmutableList.of(2, 3);
    private static final List<Integer> DATA3 = ImmutableList.of(4, 5, 6);

    @Test
    public void testCapacity() {
        Iterator<Integer> results;

        results = new ListIterator<>(0, EMPTY);
        Assert.assertFalse(results.hasNext());
        Assert.assertEquals(0, Iterators.size(results));

        results = new ListIterator<>(2, DATA1.iterator());
        Assert.assertTrue(results.hasNext());
        Assert.assertEquals(1, Iterators.size(results));

        results = new ListIterator<>(2, DATA2.iterator());
        Assert.assertTrue(results.hasNext());
        Assert.assertEquals(2, Iterators.size(results));

        Assert.assertThrows(IllegalArgumentException.class, () -> {
            new ListIterator<>(0, DATA1.iterator());
        });

        Assert.assertThrows(IllegalArgumentException.class, () -> {
            new ListIterator<>(2, DATA3.iterator());
        });
    }

    @Test
    public void testList() {
        ListIterator<Integer> results;

        results = new ListIterator<>(-1, EMPTY);
        Assert.assertEquals(ImmutableList.of(), results.list());

        results = new ListIterator<>(-1, DATA1.iterator());
        Assert.assertEquals(ImmutableList.of(1), results.list());

        results = new ListIterator<>(-1, DATA2.iterator());
        Assert.assertEquals(ImmutableList.of(2, 3), results.list());

        results = new ListIterator<>(-1, DATA3.iterator());
        Assert.assertEquals(ImmutableList.of(4, 5, 6), results.list());
    }

    @Test
    public void testHasNext() {
        Iterator<Integer> origin = DATA1.iterator();
        Assert.assertTrue(origin.hasNext());

        Iterator<Integer> results = new ListIterator<>(-1, origin);
        Assert.assertTrue(results.hasNext());
        Assert.assertTrue(results.hasNext());
        Assert.assertFalse(origin.hasNext());
    }

    @Test
    public void testNext() {
        Iterator<Integer> results = new ListIterator<>(-1, DATA1.iterator());
        Assert.assertEquals(1, (int) results.next());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results.next();
        });
    }

    @Test
    public void testNextAfterList() {
        Iterator<Integer> results = new ListIterator<>(-1, DATA1.iterator());
        Assert.assertEquals(ImmutableList.of(1),
                            ((ListIterator<?>) results).list());
        Assert.assertEquals(1, (int) results.next());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results.next();
        });
    }

    @Test
    public void testNextWithMultiTimes() {
        Iterator<Integer> results = new ListIterator<>(-1, DATA2.iterator());
        Assert.assertEquals(2, (int) results.next());
        Assert.assertEquals(3, (int) results.next());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results.next();
        });
    }

    @Test
    public void testHasNextAndNext() {
        Iterator<Integer> results = new ListIterator<>(-1, DATA1.iterator());
        Assert.assertTrue(results.hasNext());
        Assert.assertTrue(results.hasNext());
        Assert.assertEquals(1, (int) results.next());
        Assert.assertFalse(results.hasNext());
        Assert.assertFalse(results.hasNext());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results.next();
        });
    }

    @Test
    public void testRemove() {
        List<Integer> list = new ArrayList<>(DATA3);
        ListIterator<Integer> results = new ListIterator<>(-1, list.iterator());

        Assert.assertEquals(ImmutableList.of(4, 5, 6), list);
        Assert.assertEquals(ImmutableList.of(4, 5, 6), results.list());

        Assert.assertThrows(UnsupportedOperationException.class, () -> {
            results.remove();
        });
        results.next();
        Assert.assertThrows(UnsupportedOperationException.class, () -> {
            results.remove();
        });

        Assert.assertEquals(ImmutableList.of(4, 5, 6), list);
        Assert.assertEquals(ImmutableList.of(4, 5, 6), results.list());
    }

    @Test
    public void testRemoveWithoutResult() {
        Iterator<Integer> results = new ListIterator<>(-1, EMPTY);
        Assert.assertThrows(UnsupportedOperationException.class, () -> {
            results.remove();
        });

        List<Integer> list0 = new ArrayList<>();
        Iterator<Integer> results2 = new ListIterator<>(-1, list0.iterator());
        Assert.assertThrows(UnsupportedOperationException.class, () -> {
            results2.remove();
        });
    }

    @Test
    public void testClose() throws Exception {
        CloseableItor<Integer> c1 = new CloseableItor<>(DATA1.iterator());

        ListIterator<Integer> results = new ListIterator<>(-1, c1);

        Assert.assertFalse(c1.closed());

        results.close();

        Assert.assertTrue(c1.closed());
    }

    @Test
    public void testListWithConstructFromList() {
        ListIterator<Integer> results;

        results = new ListIterator<>(ImmutableList.of());
        Assert.assertEquals(ImmutableList.of(), results.list());

        results = new ListIterator<>(DATA1);
        Assert.assertEquals(ImmutableList.of(1), results.list());

        results = new ListIterator<>(DATA2);
        Assert.assertEquals(ImmutableList.of(2, 3), results.list());

        results = new ListIterator<>(DATA3);
        Assert.assertEquals(ImmutableList.of(4, 5, 6), results.list());
    }

    @Test
    public void testHasNextAndNextWithConstructFromList() {
        ListIterator<Integer> results0 = new ListIterator<>(ImmutableList.of());
        Assert.assertFalse(results0.hasNext());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results0.next();
        });

        ListIterator<Integer> results1 = new ListIterator<>(DATA1);
        Assert.assertTrue(results1.hasNext());
        Assert.assertEquals(1, results1.next());
        Assert.assertFalse(results1.hasNext());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results1.next();
        });

        ListIterator<Integer> results3 = new ListIterator<>(DATA3);
        Assert.assertTrue(results3.hasNext());
        Assert.assertEquals(4, results3.next());
        Assert.assertTrue(results3.hasNext());
        Assert.assertEquals(5, results3.next());
        Assert.assertTrue(results3.hasNext());
        Assert.assertEquals(6, results3.next());
        Assert.assertFalse(results3.hasNext());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results3.next();
        });
    }

    @Test
    public void testNextWithConstructFromList() {
        ListIterator<Integer> results0 = new ListIterator<>(ImmutableList.of());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results0.next();
        });

        ListIterator<Integer> results3 = new ListIterator<>(DATA3);
        Assert.assertEquals(4, results3.next());
        Assert.assertEquals(5, results3.next());
        Assert.assertEquals(6, results3.next());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results3.next();
        });
    }

    @Test
    public void testNextAfterListWithConstructFromList() {
        ListIterator<Integer> results3 = new ListIterator<>(DATA3);
        Assert.assertEquals(ImmutableList.of(4, 5, 6), results3.list());
        Assert.assertEquals(4, results3.next());
        Assert.assertEquals(5, results3.next());
        Assert.assertEquals(6, results3.next());
        Assert.assertThrows(NoSuchElementException.class, () -> {
            results3.next();
        });
    }
}
