%%-------------------------------------------------------------------
%% File    : con2hrl.erl
%% Author  : Ulf Wiger <ulf@wiger.net>
%% Description : 
%%
%% Created :  7 Apr 2003 by Ulf Wiger <ulf@wiger.net>
%%-------------------------------------------------------------------
%% ``The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
%% 
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%% 
%% The Initial Developer of the Original Code is Ulf Wiger.''

-module(con2hrl).

-export([file/1, file/2]).

-import(proplists, [get_value/2]).

file(ContractF) ->
    file(ContractF, []).

%% Mode : abort | overwrite
%%
file(ContractF0, Opts0) ->
    ContractF = to_string(ContractF0),
    Opts = default_opts(ContractF, Opts0),
    OutFile = get_value(outfile, Opts),
    case {file:read_file_info(OutFile),get_value(overwrite, Opts)} of
	{{ok, _}, false} ->
	    exit(hrl_exists);
	_ ->
	    {ok,Contract} = contract_parser:file1(ContractF),
	    {ok,Fd} = file:open(OutFile, [write]),
	    write_hrl(Contract, OutFile, Fd),
	    file:close(Fd)
    end.



write_hrl({contract,Name,Vsn, Types, States, AnyState}, File, Fd) ->
    io:fwrite(Fd, 
	      "%% File:        ~s~n"
	      "%% Date:        ~s~n"
	      "%% Description: Generated from ~s.con~n",
	      [filename:basename(File), format_date(), Name]),
    make_records(Types, Fd).


make_records([{Type, {tuple, [{constant,Type}|Rest]},_}|Types], Fd) ->
    case lists:foldr(
	   fun(_, false) ->
		   false;
	      ({prim,Attr}, Acc) ->
		   case lists:member(Attr, Acc) of
		       true ->
			   false;
		       false ->
			   [Attr | Acc]
		   end;
	      (_, Acc) ->
		   false
	   end, [], Rest) of
	false ->
	    skip;
	Attrs ->
	    Head = "-record(" ++ atom_to_list(Type) ++ ", {",
	    Pad = lists:duplicate(length(Head), $\s),
	    Tail = case Attrs of
		       [Attr] ->
			   atom_to_list(Attr) ++ "}).\n";
		       [H|T] ->
			   atom_to_list(H) ++ 
			       [[",\n", Pad, atom_to_list(Ax)] ||
				   Ax <- T] ++ "}).\n";
		       [] ->
			   skip
		   end,
	    io:fwrite(Fd, "\n" ++ Head ++ Tail, [])
    end,
    make_records(Types, Fd);
make_records([_|Types], Fd) ->
    make_records(Types, Fd);
make_records([], Fd) ->
    ok.


format_date() ->
    {Y,M,D} = date(),
    {HH,MM,SS} = time(),
    [il(Y),"-",il(M),"-",il(D),", ",il(HH),":",il(MM),":",il(SS)].

il(I) ->
    pad0(integer_to_list(I)).

pad0([N]) ->
    [$0,N];
pad0(Other) ->
    Other.


default_opts(ContractF, Opts) ->
    outfile(ContractF, Opts).
outfile(CF, Opts0) ->
    Opts = case get_value(outfile, Opts0) of
	       undefined ->
		   OutF = case regexp:split(CF, "\\.") of
			      {ok, [Base, "con"]} ->
				  Base ++ ".hrl";
			      Other ->
				  exit({unexpected, Other})
			  end,
		   [{outfile, OutF}|Opts0];
	       OutF ->
		   lists:keyreplace(
		     outfile, 1, Opts0, {outfile, to_string(OutF)})
	   end,
    overwrite(CF, Opts).
overwrite(CF, Opts0) ->
    case get_value(overwrite, Opts0) of
	undefined ->
	    [{overwrite, true}|Opts0];
	_ ->
	    Opts0
    end.
	    
to_string(A) when is_atom(A) ->
    atom_to_list(A);
to_string(S) when is_list(S) ->
    S.
