#!/usr/bin/env escript
%% -*- erlang -*-

-mode(compile).

main([]) ->
    try
	{ok, Dir0} = file:get_cwd(),
	Dir = filename:dirname(Dir0),

	%% Include special chars used in wings
	Special = lists:sort([$¦, $✓]),
	Start = array:from_orddict([{S,1} || S <- Special], 0),

	Latin1 = ["en","de","es","fi","sv","it","pt"],
	Latin1Chars = scan(Latin1, Dir, Start),
	analyze(Latin1Chars, 5),

	WEuro  = ["cs","hu","fr","pl"],
	%% WEuroChars = scan(WEuro, Dir, Latin1Chars),
	%% analyze(WEuroChars, 5),

	EEuro  = ["tr", "ru"],
	%% EEuroChars = scan(EEuro, Dir, Latin1Chars),
	%% analyze(EEuroChars, 5),

	{ok, Fd} = file:open("wings_chars.hrl", [write]),
	io:format(Fd, "%%~n%% This file is generated by gen_char_hrl do not edit~n%%~n", []),

	EuroChars = scan(EEuro ++ WEuro, Dir, Latin1Chars),
	write(Fd, "euro", analyze(EuroChars, 5)),

	KoreanChars = scan(["ko"], Dir, Latin1Chars),
	write(Fd, "ko", analyze(KoreanChars, 5)),

	JapanChars = scan(["jp"], Dir, Latin1Chars),
	write(Fd, "jp", analyze(JapanChars, 5)),

	SiChChars = scan(["zh-cn"], Dir, Latin1Chars),
	write(Fd, "zh_cn", analyze(SiChChars, 5)),
	
	TrChChars = scan(["zh-tw"], Dir, Latin1Chars),
	write(Fd, "zh_tw", analyze(TrChChars, 5)),

	file:close(Fd),
	%[analyze(Res, Size) || Size <- lists:seq(5, 55, 5)],
	halt(0)
    catch _:Reason ->
	    io:format("Error: ~p in ~p~n",[Reason, erlang:get_stacktrace()]),
	    halt(128)
    end.

scan([Lang|Langs], Dir, Acc) ->
    Res = filelib:fold_files(Dir, ".*" ++ Lang ++ ".lang$", true, fun handle/2, Acc),
    scan(Langs, Dir, Res);
scan([], _, Acc) -> 
    Acc.

analyze(Res, Size) ->
    [{Key,_}|OD] = array:sparse_to_orddict(Res),
    Regions = analyze_1(OD, Size, Key, Key, []),
    %% RegionsSize = [1+End-Start || {Start, End} <- Regions],
    %% io:format("Size: ~p Uniq ~p Regions ~p ", [Size, length(OD)+1, length(Regions)]),
    %% io:format("Chars ~p min ~p max ~p~n",[lists:sum(RegionsSize),
    %% 					  lists:min(RegionsSize),
    %% 					  lists:max(RegionsSize)]),
    %% io:format("~p  ~p  ~p~n", [Size, length(Regions), lists:sum(RegionsSize)]),
    Regions.

analyze_1([{Char,_}|Chars], Size, Start, End, Acc) ->
    case End+Size >= Char of
	true -> analyze_1(Chars, Size, Start, Char, Acc);
	_ ->
	    analyze_1(Chars, Size, Char, Char, [{Start, End}|Acc])
    end;
analyze_1([], _, Start, End, Acc) ->
    lists:reverse([{Start, End}|Acc]).

write(Fd, What, List) ->
    io:format(Fd, "~n~n-define(WINGS_CHARS_~s,~n [", [string:to_upper(What)]),
    list_regions(List, 0, Fd).

list_regions([{Start, Start}|Rs], Line, Fd) when Line < 70 ->
    Str = case Rs of
	      [] -> io_lib:format("~p", [Start]);
	      _  -> io_lib:format("~p,", [Start])
	  end,
    Len = length(lists:flatten(Str)),
    io:format(Fd, "~s", [Str]),
    list_regions(Rs, Line + Len, Fd);
list_regions([{Start, End}|Rs], Line, Fd) when Line < 70 ->
    Str = case Rs of
	      [] -> io_lib:format("{~.7p,~.7p}", [Start, End]);
	      _  -> io_lib:format("{~.7p,~.7p},", [Start, End])
	  end,
    Len = length(lists:flatten(Str)),
    io:format(Fd, "~s", [Str]),
    list_regions(Rs, Line + Len, Fd);
list_regions([], _Line, Fd) ->
    io:format(Fd, "]).~n", []);
list_regions(Rs, _Line, Fd) ->
    io:format(Fd, "~n  ", []),
    list_regions(Rs, 0, Fd).

handle(File, Acc) ->
    try
        {ok, Data} = file:consult(File),
        lists:foldl(fun parse_data/2, Acc, Data)
   catch error:Reason ->
        io:format("Failed to parse the language file:\n ~ts\n", [File]),
        case Reason of
            {badmatch,{error,{Line,erl_parse,Msg}}} ->
                io:format(" Msg: ~p\n Tip: Check line prior to ~w\n", [lists:flatten(Msg), Line]);
            _ -> ok
        end,
        erlang:error(Reason)
    end.

parse_data({Atom, Data}, Acc) when is_atom(Atom) ->
    parse_data(Data, Acc);
parse_data({Int, Data}, Acc) when is_integer(Int) ->
    parse_data(Data, Acc);
parse_data(Chars = [Char|_], Acc) when is_integer(Char) ->
    Incr = fun(Char1, Acc0) when is_integer(Char1) ->
		   case Char1 > 10 of
		       true ->
			   array:set(Char1, 1+array:get(Char1,Acc0), Acc0);
		       false ->
			   Acc0
		   end
	   end,
    lists:foldl(Incr, Acc, Chars);
parse_data([Head|List], Acc) ->
    parse_data(List, parse_data(Head, Acc));
parse_data([], Acc) ->
    Acc.
