//TestLinkedListOperations.java
//Illustrates most of what are (probably) the most useful and
//frequently used LinkedList methods. As you experiment with this
//program, you should check the official LinkedList documentation
//and compare what you see there with what you see here.
//See TestLinkedList_toArray.java for ilustrations of toArray().
//But note that you must always decide carefully which kind of
//implentation you should use for a given application.

import java.util.LinkedList;
import java.util.Arrays;

public class TestLinkedListOperations
{
    public static void main(String[] args)
    {
        //Illustrates the default constructor and methods add(value),
        //and size(), as well as indexOf(value) and lastIndexOf(value).
        //Creates a new (empty) LinkedList of Integer and displays its size.
        //Then adds some values and displays the size again.
        //Note that autoboxing happens as the values are added.
        //Then displays the first and last index locations of the value 2.
        //Finally, displays all of the values.
        System.out.println("=====1==============================");
        LinkedList<Integer> linkedList1 = new LinkedList<>();
        System.out.println("Size = " + linkedList1.size());
        linkedList1.add(5);
        linkedList1.add(2);
        linkedList1.add(9);
        linkedList1.add(4);
        linkedList1.add(7);
        linkedList1.add(2);
        System.out.println("Size = " + linkedList1.size());
        System.out.println("First index of 2 = " + linkedList1.indexOf(2));
        System.out.println("Last index of 2 = " + linkedList1.lastIndexOf(2));
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();

        //Illustrates methods add(index, value), contains(value)
        //remove(index) and remove(value), removeIf(condition),
        //as well as how to remove a range of values, which involves
        //the use of subList(start, end).
        System.out.println("=====2==============================");
        System.out.println("Is 6 present? " + linkedList1.contains(6));
        linkedList1.add(3, 6);
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("Is 6 present? " + linkedList1.contains(6));
        linkedList1.remove(5); //Note carefully. Compare with remove() below.
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();
        Integer iObj = 5;
        linkedList1.remove(iObj); //Note carefully. Compare with remove() above.
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();
        linkedList1.removeIf(i -> i % 2 == 1);
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();
        //linkedList1.removeRange(1, 3);
        //Somewhat surprisingly, the above line will not compile.
        //The reason is simple: it's a protected method. The reason
        //it's protected is a little more complicated and we do not
        //discuss it here. Google will fill you in ...
        //Here's the alternative:
        linkedList1.subList(1, 3).clear();
        for (int i : linkedList1)
        {
            System.out.print(i + " ");
        }
        System.out.println();

        //Illustrates LinkedList constructor that takes a container as input.
        //Uses the same values as for the first container.
        System.out.println("=====3==============================");
        LinkedList<Integer> linkedList2 =
            new LinkedList<>(Arrays.asList(5, 2, 9, 4, 7, 2));
        for (int i : linkedList2)
        {
            System.out.print(i + " ");
        }
        System.out.println();

        //Illustrate clear() and isEmpty().
        System.out.println("=====4==============================");
        linkedList2.clear();
        for (int i : linkedList2)
        {
            System.out.print(i + " ");
        }
        System.out.println("\nAbove line contains values after clear().");
        if (linkedList2.isEmpty())
        {
            System.out.println("The LinkedList is now empty.");
        }

        //Illustrate sort(), the default version as well as two
        //different lambda functions for determining how to sort.
        LinkedList<Integer> linkedList3 =
            new LinkedList<>(Arrays.asList(5, 2, 9, 4, 7, 2));
        linkedList3.sort(null); //Sorts using the "natural order"
        for (int i : linkedList3)
        {
            System.out.print(i + " ");
        }
        System.out.println();
        //The following two lines both sort in reverse,
        //but the second is the preferred option.
        linkedList3.sort((i1, i2) -> i2 - i1);
        linkedList3.sort((i1, i2) -> Integer.compare(i2, i1));
        for (int i : linkedList3)
        {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
/*  Output:
    =====1==============================
    Size = 0
    Size = 6
    First index of 2 = 1
    Last index of 2 = 5
    5 2 9 4 7 2
    =====2==============================
    Is 6 present? false
    5 2 9 6 4 7 2
    Is 6 present? true
    5 2 9 6 4 2
    2 9 6 4 2
    2 6 4 2
    2 2
    =====3==============================
    5 2 9 4 7 2
    =====4==============================

    Above line contains values after clear().
    The LinkedList is now empty.
    2 2 4 5 7 9
    9 7 5 4 2 2
*/

/*
    Just a note in passing ... below is another way to create
    an LinkedList (of strings), which would require these imports:
    import java.util.Collections;
    import java.util.stream.Stream;

    Stream.of("xyz", "abc").collect(Collectors.toList());
    You can ignore this approach for the time being.
*/
