%% to compile: erlc day3A.erl
%% to run: erl -noshell -s day5 solve
%%
-module(day5).

-export ([solve/0, solve/1, solve/2]).
-export ([read_input/0]).

solve() ->
    solve(['1']),
    solve(['2']),
    init:stop().

solve(A) ->
    solve(A, read_input()).

solve(['1'], D) ->
    io:format("The solution to ~p puzzle1 is: ~p~n", [?MODULE, solve(1, D)]);
solve(1, D) ->
    solution1(D);
solve(['2'], D) ->
    io:format("The solution to ~p puzzle2 is: ~p~n", [?MODULE, solve(2, D)]);
solve(2, D) ->
    solution2(D).

read_input() ->
    {ok, IO} = file:open("input.txt", 'read'),
    Data = read_input(IO),
    file:close(IO),
    Data.

read_input(IO) ->
	read_input(IO, []).

read_input(IO, Input) ->
    case read_line(IO) of
	'eof' ->
              lists:map(fun([{X1,Y1},{X2,Y2}]) ->
              case X1 > X2 orelse (X1 == X2 andalso Y1 > Y2) of
                      'true' ->  [{X2,Y2},{X1,Y1}];
                      'false' -> [{X1,Y1},{X2,Y2}]
              end
              end, Input);
	Line -> read_input(IO, Input ++ [Line])
    end.

read_line(IO) ->
	case file:read_line(IO) of
		'eof' -> 'eof';
		{ok, Line} -> parse_line(Line)
	end.

parse_line(Line) ->
    Points = string:tokens(Line, " ,->\n"),
    [X1, Y1, X2, Y2] = [list_to_integer(X) || X <- Points],
    [{X1, Y1},{X2,Y2}].

solution1(Input) ->
   HV = get_hor_vert(Input),
   Points = lists:sort(
	      lists:flatten(
		[[{X,Y} || X <- lists:seq(X1, X2, case X1 =< X2 of 'true' -> 1; _ -> -1 end),
			   Y <- lists:seq(Y1, Y2, case Y1 =< Y2 of 'true' -> 1; _ -> -1 end)] || [{X1,Y1},{X2,Y2}] <- HV]
	       )
	     ),
   Count = count_duplicates(Points),
   Count.

solution2(Input) ->
   Points = get_all_points(Input),
   Count = count_duplicates(lists:sort(Points)),
   Count.


get_hor_vert(Input) ->
    lists:filter(fun([{X1, Y1},{X2,Y2}]) -> X1 == X2 orelse Y1 == Y2 end, Input).

get_all_points(Input) ->
    get_all_points(Input, []).

get_all_points([], Acc) -> 
	Acc;
get_all_points([[{X1,Y1},{X2,Y2}]|Rest], Acc) when X1 ==  X2 ->
	get_all_points(Rest, Acc ++ [{X1, Y} ||  Y <- lists:seq(Y1,Y2)]);
get_all_points([[{X1,Y1},{X2,Y2}]|Rest], Acc) when Y1 ==  Y2 ->
	get_all_points(Rest, Acc ++ [{X, Y1} ||  X <- lists:seq(X1,X2)]);
get_all_points([[{X1,Y1},{X2,Y2}]|Rest], Acc) when Y1 < Y2 ->
	get_all_points(Rest, Acc ++ [{X, Y1-X1+X} ||  X <- lists:seq(X1,X2)]);
get_all_points([[{X1,Y1},{X2,Y2}]|Rest], Acc) when Y1 > Y2 ->
	get_all_points(Rest, Acc ++ [{X, (-1 *  X) + X1 + Y1 } ||  X <- lists:seq(X1,X2)]).

count_duplicates(Points) ->
	count_duplicates(Points, []).

count_duplicates([], Count) -> 
	lists:foldl(fun({X, _P}, Acc) ->
		  case X > 1 of 'true' -> Acc + 1; _ -> Acc  end end, 0, Count);
count_duplicates([H|T], Count) ->
	case T /= [] andalso hd(T) == H of
             'true' ->  count_duplicate(H, T, Count, 1);
             _Else -> count_duplicates(T, Count ++ [{1, H}])
        end.

count_duplicate(H, [H|T], Count, X) ->
    count_duplicate(H, T, Count, X + 1);
count_duplicate(H, List, Count, X) ->
	count_duplicates(List, Count ++ [{X, H}]).



