class TupleCombinationGenerator {

    public static <T> List<List<T>> generateCombinations(List<? extends Iterable<T>> inputLists) {
        if (inputLists.isEmpty()) {
            return Collections.emptyList();
        }
        List<List<T>> results = new ArrayList<List<T>>();
        Iterable<T> currentList = inputLists.get(0);
        if (inputLists.size() == 1) {
            for (T object : currentList) {
                // This is the last list in the input lists supplied - processed first due to eager recursion below.
                // Add each object in this input list as a single element in its own new LinkedList.
                // The other branch will subsequently add objects from preceding input lists
                // to the _start_ of this LinkedList. We use LinkedList to avoid shuffling elements.
                results.add(new LinkedList<T>(Collections.singleton(object)));
            }
        }
        else {
            // Start processing objects from the first input list supplied,
            // but note that we will call this method recursively before we move on to the next object...
            for (T object : currentList) {
                // Prepare a tail list of the input lists (the input lists after this first one).
                // The tail list is actually a _view_ onto the original input lists, (no data is copied)...
                List<? extends Iterable<T>> tail = inputLists.subList(1, inputLists.size());
                // Call this method recursively, getting the first objects in the tail lists first...
                for (List<T> permutations : generateCombinations(tail)) {
                    // Insert the object from the first list at the _start_ of the permutations list...
                    permutations.add(0, object);
                    // As the stack unwinds, we have assembled permutations in the correct order.
                    // Add each permutation to results, to return to the preceding stack frame or to the caller...
                    results.add(permutations);
                }
            }
        }
        return results;
    }

      TupleCombinationGenerator();

}