%% ``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 Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%% 
%%     $Id$
%%
-module(pman_options).

%% Window with trace options settings (File->Options...)

-export([dialog/3,
	 read_from_file/1, save_to_file/2]).

-include("pman_options.hrl").

-define(WIN_WIDTH,  350).
-define(WIN_HEIGHT, 350).

-define(TOP_WINDOW, xx_pman_option_window_xx).
-define(TOP_FRAME,  xx_pman_top_frame_xx).

-record(state, {resize_frame,   % GS identifier for the main frame
		parent}).       % Pid of parent

%%--dialog/3------------------------------------------------------------
%% Create a window, or return a value indicating that is is already
%% created.

dialog(ParentWin, Title, Options) ->
    Self = self(),
    Pid = spawn(fun() -> dialog(Self, ParentWin, Title, Options) end),
    receive
	{Pid, Value} ->
	    Value % Options2 | {error,destroyed} | {error,cancelled}
    end.

dialog(Parent, ParentWin, Title, Options) ->

    %% Check if the dialog has already been created, in that 
    %% case, we can reuse it. Otherwise a new dialog is created.
    case gse:name_occupied(?TOP_WINDOW) of
	false -> make_window(ParentWin, Title);
	true -> ok
    end,

    %% Window has now been created or may be re-used
    update_window_from_options(Options),

    gse:resize(?TOP_FRAME, ?WIN_WIDTH, ?WIN_HEIGHT),
    gse:map(?TOP_WINDOW),

    loop(#state{resize_frame=?TOP_FRAME, parent=Parent}).

loop(State) ->
    receive
	{gs, _Id, destroy, _Data, _Arg} -> 
	    State#state.parent ! {self(), {error,destroyed}};

	{gs, ?TOP_WINDOW, configure, _Data, [W, H |_]} ->
	    gse:config(State#state.resize_frame,
		       [{width,W},{height,H}]), % repack
	    loop(State);

	{gs, ok_button, click, _Data, _Arg} ->
	    Options = get_options_from_window(),
	    gse:unmap(?TOP_WINDOW),
	    State#state.parent ! {self(), Options};

	{gs, cancel_button, click, _Data, _Arg} ->
	    gse:unmap(?TOP_WINDOW),
	    State#state.parent ! {self(), {error,cancelled}};

	{gs, trace_spawn, click, _Data, [_Text,_,Value]} ->
	    group_radio(Value, trace_spawn_all, [trace_spawn_all,
						 trace_spawn_first]),
	    loop(State);

	{gs, trace_link, click, _Data, [_Text,_,Value]} ->
	    group_radio(Value, trace_link_all, [trace_link_all,
						trace_link_first]),
	    loop(State);

	{gs, trace_in_window, click, _Data, _Arg} ->
	    lists:foreach(fun(X) -> gse:disable(X) end,
			  [trace_file, trace_file_browse]),
	    loop(State);

	{gs, trace_to_file, click, _Data, [_Text,_,_Value]} ->
	    lists:foreach(fun(X) -> gse:enable(X) end,
			  [trace_file, trace_file_browse]),
	    loop(State);

	{gs, trace_file_browse, click, _Data, _Arg} ->
	    Result = tool_utils:file_dialog([{type,save},
					     {file, "Untitled.log"}]),
	    case Result of
		{error, _Reason} ->
		    loop(State);
		{ok, Name,_State} ->
		    gse:config(trace_file, [{text, Name}]),
		    loop(State)
	    end
    end.

-define(LBLOPTS, [{justify,left}, {align,w}]).
-define(BTNOPTS, [{justify,left}, {align,w}]).

make_window(ParentWin, Title) ->

    Font = pman_win:font(),

    gse:named_window(?TOP_WINDOW, ParentWin, [{title,Title},
					      {configure,true},
					      {width, ?WIN_WIDTH},
					      {height, ?WIN_HEIGHT}]),

    gse:named_frame(?TOP_FRAME, ?TOP_WINDOW,
		    [{bw,3},
		     {packer_x,[{stretch,1,175}, {stretch,1,175}]},
		     {packer_y,[{stretch,3},{stretch,2},{stretch,1}]}]),

    F11 = gse:frame(?TOP_FRAME, [{bw,3},
				 {pack_xy,{1,1}},
				 {packer_x,[{stretch,1},
					    {stretch,20},
					    {stretch,2}]},
				 {packer_y,[{stretch,2},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1}]}]),

    gse:label(F11,[{pack_xy,{2,1}},
		   {label,{text,"Trace output options:"}},
		   {font,Font} | ?LBLOPTS]),

    gse:named_checkbutton(trace_send, F11,
			  [{pack_xy,{2,2}},
			   {label,{text,"Trace send"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_checkbutton(trace_receive, F11,
			  [{pack_xy,{2,3}},
			   {label,{text, "Trace receive"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_checkbutton(trace_functions,F11,
			  [{pack_xy,{2,4}},
			   {label,{text, "Trace functions"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_checkbutton(trace_events,F11,
			  [{pack_xy,{2,5}},
			   {label,{text, "Trace events"}},
			   {font,Font} | ?BTNOPTS]),

    F21 = gse:frame(?TOP_FRAME, [{bw,3},
				 {pack_xy,{2,1}},
				 {packer_x,[{stretch,1},
					    {stretch,2},
					    {stretch,2},
					    {stretch,20},
					    {stretch,1}]},
				 {packer_y,[{stretch,2},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1}]}]),

    gse:label(F21, [{pack_xy,{{2,4},1}},
		    {label,{text,"Inheritance options:"}},
		    {font,Font} | ?LBLOPTS]),

    gse:named_checkbutton(trace_spawn, F21,
			  [{pack_xy,{{2,4},2}},
			   {data,trace_send},
			   {label,{text,"Inherit on spawn"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_radiobutton(trace_spawn_all, F21,
			  [{pack_xy,{{3,4},3}},
			   {group,spawn},
			   {data,trace_receive},
			   {label,{text, "All spawns"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_radiobutton(trace_spawn_first, F21,
			  [{pack_xy,{{3,4},4}},
			   {group,spawn},
			   {data,trace_receive},
			   {label,{text,"First spawn only"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_checkbutton(trace_link, F21,
			  [{pack_xy,{{2,4},6}},
			   {data,trace_send},
			   {label,{text,"Inherit on link"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_radiobutton(trace_link_all, F21,
			  [{pack_xy,{{3,4},7}},
			   {group,link},
			   {data,trace_receive},
			   {label,{text,"All links"}},
			   {font,Font} | ?BTNOPTS]),

    gse:named_radiobutton(trace_link_first, F21,
			  [{pack_xy,{{3,4},8}},
			   {group,link},
			   {data,trace_receive},
			   {label,{text,"First link only"}},
			   {font,Font} | ?BTNOPTS]),

    F12 = gse:frame(?TOP_FRAME, [{bw,3},
				 {pack_xy,{{1,2},2}},
				 {packer_x,[{stretch,1},
					    {stretch,5},  % Label
					    {stretch,1},
					    {stretch,10}, % Field
					    {stretch,1},
					    {stretch,5},  % Button
					    {stretch,1}]},
				 {packer_y,[{stretch,2},
					    {stretch,1},
					    {stretch,1},
					    {stretch,1}]}]),
    
    gse:label(F12, [{pack_xy,{{2,6},1}},
		    {label,{text,"Trace output options:"}},
		    {font,Font} | ?LBLOPTS]),
    gse:named_radiobutton(trace_in_window, F12,
			  [{pack_xy,{{2,6},2}},
			   {group, trace_dest},
			   {label,{text,"In window"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_radiobutton(trace_to_file, F12,
			  [{pack_xy,{2,3}},
			   {group, trace_dest},
			   {label,{text,"To file"}},
			   {font,Font} | ?BTNOPTS]),
    gse:named_entry(trace_file, F12, [{pack_xy,{4,3}}, {font,Font}]),
    gse:named_button(trace_file_browse, F12,
		     [{pack_xy,{6,3}},
		      {label,{text," Browse..."}},
		      {font,Font} | ?BTNOPTS]),

    F13 = gse:frame(?TOP_FRAME, [{bw,3},
				 {pack_xy,{{1,2},3}},
				 {packer_x,[{stretch, 1},
					    {fixed, 60},
					    {stretch, 1},
					    {fixed, 60},
					    {stretch, 1}]},
				 {packer_y,[{stretch,1},
					    {fixed, 30},
					    {stretch,1}]}]),
    
    gse:named_button(ok_button, F13, [{pack_xy,{2,2}},
				      {label,{text,"OK"}},
				      {font,Font}]),
    gse:named_button(cancel_button, F13, [{pack_xy,{4,2}},
					  {label,{text,"Cancel"}},
					  {font,Font}]).

update_window_from_options(Options) ->

    %% Trace output
    gse:config(trace_send, [{select,Options#trace_options.send}]),
    gse:config(trace_receive,
	       [{select,Options#trace_options.treceive}]),
    gse:config(trace_functions,
	       [{select,Options#trace_options.functions}]),
    gse:config(trace_events, [{select,Options#trace_options.events}]),

    %% Trace inheritance
    case (Options#trace_options.inherit_on_all_spawn or
	  Options#trace_options.inherit_on_1st_spawn) of
	true ->
	    gse:select(trace_spawn),
	    gse:config(trace_spawn_all,
		       [{select,Options#trace_options.inherit_on_all_spawn}]),
	    gse:config(trace_spawn_first,
		       [{select,Options#trace_options.inherit_on_1st_spawn}]);
	false ->
	    lists:foreach(fun(X) -> gse:disable(X) end,
			  [trace_spawn_all,trace_spawn_first])
    end,

    case (Options#trace_options.inherit_on_all_link or
	  Options#trace_options.inherit_on_1st_link) of
	true -> gse:select(trace_link),
		gse:config(trace_link_all,
			   [{select,Options#trace_options.inherit_on_all_link}]),
		gse:config(trace_link_first,
			   [{select, Options#trace_options.inherit_on_1st_link}]);
	false ->
	    lists:foreach(fun(X) -> gse:disable(X) end,
			  [trace_link_all,trace_link_first])
    end,

    %% Trace ouput destinations
    gse:config(trace_in_window,
	       [{select,(not Options#trace_options.to_file)}]),

    gse:config(trace_to_file, [{select,Options#trace_options.to_file}]),
    gse:config(trace_file, [{text,Options#trace_options.file}]),
    case Options#trace_options.to_file of
	true ->
	    ok;
	false ->
	    lists:foreach(fun(X) -> gse:disable(X) end,
			  [trace_file, trace_file_browse])
    end.

get_options_from_window() ->
    #trace_options{send = gse:read(trace_send,select),
		   treceive = gse:read(trace_receive,select),
		   functions = gse:read(trace_functions,select),
		   events = gse:read(trace_events,select),
		   inherit_on_1st_spawn = gse:read(trace_spawn_first,select),
		   inherit_on_all_spawn = gse:read(trace_spawn_all,select),
		   inherit_on_1st_link = gse:read(trace_link_first,select),
		   inherit_on_all_link = gse:read(trace_link_all,select),
		   to_file = gse:read(trace_to_file,select),
		   file = gse:read(trace_file,text)}.

group_radio(Value, Default, GroupList) ->
    case Value of
	true ->
	    gse:select(Default),
	    lists:foreach(fun(X) -> gse:enable(X) end, GroupList);
	false ->
	    lists:foreach(fun(X) -> gse:deselect(X) end, GroupList),
	    lists:foreach(fun(X) -> gse:disable(X) end, GroupList)
    end.

%%--read_from_file/(File)-----------------------------------------------
%% Returns the options saved in File.
%% If no options can be found, then the default options are
%% returned.

read_from_file(File) ->
    case file:consult(File) of
	{ok, [Term]} ->
	    if
		is_record(Term, trace_options) ->
		    {ok, Term};
		true ->
		    {error, "unexpected contents", #trace_options{}}
	    end;
	{ok, _Terms} ->
	    {error, "unexpected contents", #trace_options{}};
	{error, Tuple} when is_tuple(Tuple) -> % {Line,Mod,Term}
	    {error, "erroneous contents", #trace_options{}};
	{error, _Posix} ->
	    %% The most probable reason is that the file does not
	    %% exist, this is not an error so we simply return
	    %% the default trace options instead
	    {ok, #trace_options{}}
    end.

%%--save_to_file(Options, File)-----------------------------------------

save_to_file(Options, File) ->
    case file:open(File, [write]) of
	{ok, Fd} ->
	    {{Year,Month,Day},{H,M,S}} = calendar:local_time(),
	    io:format(Fd, "%%%~n", []),
	    io:format(Fd, "%%% File: ~s~n", [File]),
	    io:format(Fd, "%%% Date: ~w-~2..0w-~2..0w, ~2..0w:~2..0w:~2..0w~n",
		      [Year,Month,Day,H,M,S]),
	    io:format(Fd, "%%%~n", []),
	    io:format(Fd, "%%% This file was created by Pman. ~n", []),
	    io:format(Fd, "%%%~n", []),
	    io:format(Fd, "%%% DO NOT EDIT! ~n", []),
	    io:format(Fd, "%%%~n", []),
	    io:format(Fd, "%%%~n", []),
	    io:format(Fd, "~p.~n", [Options]),
	    file:close(Fd),
	    ok;
	{error, Posix} ->
	    {error, file:format_error(Posix)}
    end.
