
-module(tutorlang).

-export([print/1,
	 hello/0, 
	 hello/1,
	 fizzbuzz/1,
	 run/0]).

print([Word|Sentence]) -> print(Word) , print(Sentence) ;
print([]) -> io:format("\n") ;
print(What) -> io:format("~p ",[What]) . 

hello(Who) -> print([hello, Who, '!!']) .
hello() -> hello(world) .

fizzbuzz([Val|Rest]) -> [fizzbuzz(Val)|fizzbuzz(Rest)] ;
fizzbuzz([]) -> [] ;
fizzbuzz(0) -> 0;
fizzbuzz(Val) when (Val rem 3) =:= 0 -> fizz ;
fizzbuzz(Val) when (Val rem 5) =:= 0 -> buzz ;
fizzbuzz(Val) -> Val .

fact(0) -> 1 ;
fact(N) -> N * fact(N-1) .

fibb(0,A,B) -> [A,B] ;
fibb(N,A,B) -> [A|fibb(N-1,B,A+B)] .
fibb(0) -> [] ;
fibb(1) -> [1] ;
fibb(N) -> fibb(N-2,1,1) .

bittian(0) -> 0;
bittian(B) when (B bsr 8) =:= 0 -> (B bor 1) * ((B + 1) bsr 1) .

transform(Funk,Collection) when is_function(Funk), is_list(Collection) -> 
	[Funk(Val) || Val <- Collection] .

filter(Funk,Collection) when is_function(Funk), is_list(Collection) ->
	[Val || Val <- Collection, Funk(Val)] .

sum([]) -> 0 ;
sum([Val|Rest]) ->  Val + sum(Rest) .

count([]) -> 0 ;
count([_|Rest]) -> 1 + count(Rest) .

withbutter([]) -> no;
withbutter([butter]) -> yes;
withbutter([butter|S]) -> yes;
withbutter([Any|S]) -> withbutter(S).

noww() -> 
	{_,Second,Milli} = os:timestamp(),
	Milli + (Second*1000).

range(N) -> lists:seq(1,N).
shuffle(List) ->
	Indexed = [{random:uniform(),Val} || Val <- List],
	Randomized = lists:sort(Indexed),
	[Item || {_,Item} <- Randomized].

bench([]) -> [];
bench([{Funk,Arg}|Rest]) -> Funk(Arg), bench(Rest).
bench(N,Funk,Arg) ->
	Test = [{Funk,Arg} || _ <- lists:seq(1,N)],
	io:format("~p~n",[Test]),
	Start = noww(),
	bench(Test),
	End = noww(),
	End-Start.

qsort([]) -> [];
qsort([Pivot|Rest]) ->
	qsort([Smaller || Smaller <- Rest, Smaller < Pivot]) ++
	[Pivot] ++
	qsort([Bigger || Bigger <- Rest, Bigger > Pivot]).

native(List) -> lists:sort(List).

run() ->
	hello(),
	hello(you),
	print(['I',am,queen,'of',faith,'!']),
	print([the,secret,'of',the,universe,'and',everything,is,42]),
	ZeroToTwenny = lists:seq(0,20,1),
	print(ZeroToTwenny),
	print(fizzbuzz(ZeroToTwenny)),
	print([factorial,'of',5,'is',fact(5)]),
	print(fibb(5)),
	print([128,bittian(128)]) ,
	print(transform(fun(A) -> A+1 end, ZeroToTwenny )),
	print(filter(fun(A) -> (A rem 2) =:= 1 end, ZeroToTwenny)),
	print([sum([1,2,3])]),
	print([count([1,2,3])]),

	print(withbutter([])),
	print(withbutter([bread])),
	print(withbutter([butter])),
	print(withbutter([truffle,butter])),
	print(withbutter([butter,scotch])),

	print([sorting]),
	Sample = shuffle(range(1000)),
	print([from,Sample]),
	print([result,qsort(Sample)]),
	%print([took,bench(1000,qsort,Sample)]),
	print([native,bench(1000,native,Sample)]),

	init:stop().

