package playingWithLists;

public class SchemeListUtil  {
	
	// concatenate two lists, resulting in a list.
	// Note that the function is declared "generic", operating
	// over a given type "Any". Whatever type will be the type
	// of the elements of the first list must be the type of the
	// elements of the second list and will be the type of the
	// elements of the result list.
	public static <Any> SchemeList<Any> 
	concat(SchemeList<Any> aList, SchemeList<Any> anotherList) {
		if (aList.isNil()) {
			return anotherList;
		} else {
			return concat(aList.cdr(),anotherList).cons(aList.car());
		}
	}
	
	// square all elements of an integer list
	// (use recursion or iteration)
	public static SchemeList<Integer> square(SchemeList<Integer> aList) {
		if (aList.isNil()) {
			return new MySchemeList<Integer>();
		} else {
			return square(aList.cdr()).cons(aList.car()*aList.car());
		}
	}

	// sum up all elements of an integer list
	// (use recursion or iteration)
	public static int sum(SchemeList<Integer> aList) {
		if (aList.isNil()) {
			return 0;
		} else {
			return aList.car() + sum(aList.cdr());
		}
	}

	// find the length of a list (use iteration)
	// note the "wildcard" type ?. The type SchemeList<?> is
	// the supertype of all SchemeList<...> types. There is
	// no need for a generic type here, because no other
	// type in the argument list or return type needs to
	// refer to the element type.
	public static int iterativeLength(SchemeList<?> aList) {
		int acc = 0;
		while (! aList.isNil()) {
			aList = aList.cdr();
			acc++;
		}
		return acc;
	}	
	
	// reverse a given list (use iteration)
	public static <Any> SchemeList<Any> iterativeReverse(SchemeList<Any> aList) {
		MySchemeList<Any> acc = new MySchemeList<Any>();
		while (! aList.isNil() ) {
			acc = acc.cons(aList.car());
			aList = aList.cdr();
		}
		return acc;
	}
	
	// concatenate all lists in a given list of lists of elements, resulting in
	// a list of elements.
	public  static <Any> SchemeList<Any> concatAll(SchemeList<SchemeList<Any>> aListList) {
		if (aListList.isNil()) {
			return new MySchemeList<Any>();
		} else {
			return concat(aListList.car(),concatAll(aListList.cdr()));
		}
	}
}
