%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%% 
%% 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 online 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.
%% 
%% %CopyrightEnd%
%%
-module(toolbar_toolconfig).
-compile([{nowarn_deprecated_function,{gs,config,2}},
          {nowarn_deprecated_function,{gs,create,3}},
          {nowarn_deprecated_function,{gs,destroy,1}},
          {nowarn_deprecated_function,{gs,read,2}},
          {nowarn_deprecated_function,{gs,start,0}}]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Erlang Toolbar
%
%%% Description %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Tool configuration tool, edit and creates .tool files
% This tool works separately from the toolbar.
%
%%% External data types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% toolinfo() -- Tool configuration information
-include("toolbar.hrl").
%
%%% Internal data types %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% tfwindow() -- Toolfile configuration window
-record(tfwindow,
	{window,
	 fileentry,
	 toolentry,moduleentry,functionentry,
	 iconentry,messageentry,htmlentry,
	 label}).
%
%%% Exports %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-export([start/0]).
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-export([init/0]). % spawn


%%% Exported functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%----------------------------------------
% start() => pid()
%----------------------------------------
start() ->
    spawn(toolbar_toolconfig,init,[]).


%%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%=============================================================================
% Main loop
%=============================================================================

%----------------------------------------
% init()
%----------------------------------------
init() ->

    %% Start GS (or get the pid if it is already running)
    S = gs:start(),

    %% Draw the window
    Window = draw_window(S),

    loop(S,Window).

%----------------------------------------
% loop(S,Window)
%   S - pid() GS
%   Window - tfwindow()
%----------------------------------------
loop(S,Window) ->
    receive

	%% 'Return' pressed in the 'File' entry
	{gs,_Obj,keypress,file,['Return'|_]} ->

	    %% Check if a file name is specified
	    case string:strip(gs:read(Window#tfwindow.fileentry,text)) of
		
		%% No file name specified, move focus to next entry
		"" ->
		    move_focus(Window,file);

		%% A name is specified
		String ->
		    
		    %% Add a .tool suffix to the file name if necessary
		    FileName = tool_file(String),
		    
		    %% Write the complete file name to the file entry
		    gs:config(Window#tfwindow.fileentry,{text,FileName}),
		    
		    %% Try to open the file
		    case file:consult(FileName) of
			
			%% File exists and seems ok
			{ok,[{version,Vsn},T]} ->
			    
			    %% Check the syntax of the file contents
			    %% (All mandatory information specified,
			    %%  correct types, etc)
			    case toolbar_lib:tool_info_syntax(Vsn,T) of
				
				%% Ok -- Show the file contents in the window
				%% and move focus to the next entry
				{ok,Info} ->
				    display(Window,"File: "++FileName++
					           " opened"),
				    clear_info(Window),
				    show_info(Window,Info),
				    move_focus(Window,file);
				
				%% Erroneous version number -- Notify user
				{error,version} ->
				    Win = Window#tfwindow.window,
				    tool_utils:notify(Win,[FileName,
				       "File has wrong version number"]);

				%% Other error -- Notify user
				_Error ->
				    Win = Window#tfwindow.window,
				    tool_utils:notify(Win,[FileName,
				       "File is in erroneous format"])
			    end;
				
			%% The file can not be read, show default values
			%% according to the file name in the window and
			%% move focus to the next entry
			_ ->
			    display(Window,"File: "++FileName ++
				    " could not be read, new file"),
			    Tool = filename:basename(FileName,".tool"),
			    clear_info(Window),
			    show_info(Window,[{tool,Tool},
					      {start,{list_to_atom(Tool),
						      start,[]}},
					      {icon,Tool++".gif"},
					      {html,Tool++".html"}]),
			    move_focus(Window,file)
		    end
	    end,
	    loop(S,Window);

	%% 'Return' pressed in another entry, move focus to next entry
	{gs,_Obj,keypress,Focus,['Return'|_]} ->
	    move_focus(Window,Focus),
	    loop(S,Window);
	
	%% Any oher keypress, clear the display
	{gs,_Obj,keypress,_Data,_Args} ->
	    display_clear(Window),
	    loop(S,Window);

	%% 'Clear' button pressed, clear the window
	{gs,_Obj,click,_Data,["Clear"|_]} ->
	    clear_info(Window),
	    loop(S,Window);

	%% 'Save' button pressed, save the given information to file
	{gs,_Obj,click,_Data,["Save"|_]} ->

	    %% Check if a file name is specified
	    case string:strip(gs:read(Window#tfwindow.fileentry,text)) of
		
		%% No file name specified, notify user
		"" ->
		    Win = Window#tfwindow.window,
		    tool_utils:notify(Win,
				      "A file name must be specified");

		%% A name is specified
		String ->
		    
		    %% Add a .tool suffix to the file name if necessary
		    FileName = tool_file(String),
		    
		    %% Write the complete file name to the file entry
		    gs:config(Window#tfwindow.fileentry,{text,FileName}),
		    
		    %% Check the other information given
		    case check_info(Window) of
		
			%% If given info is correct, try to save
			%% it to the file
			{ok,ToolInfo} ->
			    Win = Window#tfwindow.window,
			    case save_info(Win,FileName,ToolInfo) of

				%% Ok, display confirmation
				ok ->
				    display(Window,
					    "Tool information saved to "++
					    FileName);

				%% Cancel, do nothing
				cancel ->
				    ignore;
				
				%% Error, display error message
				{error,Reason} ->
				    display(Window,
					    toolbar_lib:error_string(Reason)++
					    FileName)
			    end;

			%% Given info incorrect, notify user
			{error,Reason} ->
			    Win = Window#tfwindow.window,
			    Str = toolbar_lib:error_string(Reason),
			    tool_utils:notify(Win,Str)
		    end
	    end,
	    loop(S,Window);

	%% 'Stop' button, close window and exit
	{gs,_Obj,click,_Data,["Stop"|_]} ->
	    gs:destroy(Window#tfwindow.window),
	    finished;

	%% Window closed, exit
	{gs,_Obj,destroy,_Data,_Args} ->
	    finished;

	Other ->
	    io:format("toolbar_toolconfig: unexp msg: ~p~n",[Other]),
	    loop(S,Window)
    end.


%=============================================================================
% Graphics
%=============================================================================

%----------------------------------------
% draw_window(S)
%   S - pid() GS
% Draw the main window.
%----------------------------------------
draw_window(S) ->

    %% -----   Open a new window   ----- 
    Win = gs:create(window,S,[{width,400},{height,390},
			      {title,"Create Tool File"}]),

    %% -----   Top frame containing a 'File name' label and entry   -----
    Top = gs:create(frame,Win,[{x,0},{y,0},{width,400},{height,60},{bw,2},
			       {keypress,true}]),

    %% File name
    gs:create(label,Top,[{x,10},{y,10},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"File name:"}}]),
    File = gs:create(entry,Top,[{x,110},{y,10},{width,280},{height,30},
				{keypress,true},{data,file}]),

    %% -----   Middle frame containing other labels and entries   -----
    Mid = gs:create(frame,Win,[{x,0},{y,60},{width,400},{height,250},{bw,2},
			       {keypress,true}]),

    %% Tool name
    gs:create(label,Mid,[{x,10},{y,10},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"Tool name:"}}]),
    Tool = gs:create(entry,Mid,[{x,110},{y,10},{width,280},{height,30},
				{keypress,true},{data,tool}]),
    
    %% Start function
    gs:create(label,Mid,[{x,10},{y,60},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"Start:"}}]),
    Mod = gs:create(entry,Mid,[{x,110},{y,60},{width,135},{height,30},
			       {keypress,true},{data,module}]),
    Fun = gs:create(entry,Mid,[{x,245},{y,60},{width,135},{height,30},
			       {keypress,true},{data,function}]),
    
    %% Icon file
    gs:create(label,Mid,[{x,10},{y,110},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"Icon file:"}}]),
    Icon = gs:create(entry,Mid,[{x,110},{y,110},{width,280},{height,30},
				{keypress,true},{data,icon}]),
    
    %% Message
    gs:create(label,Mid,[{x,10},{y,160},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"Message:"}}]),
    Msg = gs:create(entry,Mid,[{x,110},{y,160},{width,280},{height,30},
			       {keypress,true},{data,message}]),
    
    %% HTML file
    gs:create(label,Mid,[{x,10},{y,210},{width,80},{height,30},{align,e},
			 {keypress,true},
			 {label,{text,"HTML:"}}]),
    Html = gs:create(entry,Mid,[{x,110},{y,210},{width,280},{height,30},
				{keypress,true},{data,html}]),

    %% -----   Bottom frame containing the buttons   -----
    Bot = gs:create(frame,Win,[{x,0},{y,310},{width,400},{height,50},
			       {bw,2},{keypress,true}]),

    gs:create(button,Bot,[{x,75},{y,10},{width,50},{height,30},
			  {keypress,true},
			  {label,{text,"Clear"}}]),
    gs:create(button,Bot,[{x,175},{y,10},{width,50},{height,30},
			  {keypress,true},
			  {label,{text,"Save"}}]),
    gs:create(button,Bot,[{x,275},{y,10},{width,50},{height,30},
			  {keypress,true},
			  {label,{text,"Stop"}}]),

    %% -----   Label for displaying help messages   -----
    Lbl = gs:create(label,Win,[{x,0},{y,360},{width,400},{height,30},{bw,2},
			       {relief,raised},
			       {keypress,true},
			       {align,c},{label,{text,""}}]),

    gs:config(Win,{map,true}),
    gs:config(File,{setfocus,true}),

    #tfwindow{window=Win,
	      fileentry=File,
	      toolentry=Tool,
	      moduleentry=Mod,
	      functionentry=Fun,
	      iconentry=Icon,
	      messageentry=Msg,
	      htmlentry=Html,
	      label=Lbl}.

%----------------------------------------
% move_focus(Window,Focus)
%   Window - tfwindow()
%   Focus - file | tool | module | function | icon | message | html | none
% Move the input focus to the entry following Focus
%----------------------------------------
move_focus(Window,file) ->
    gs:config(Window#tfwindow.toolentry,{setfocus,true});
move_focus(Window,tool) ->
    gs:config(Window#tfwindow.moduleentry,{setfocus,true});
move_focus(Window,module) ->
    gs:config(Window#tfwindow.functionentry,{setfocus,true});
move_focus(Window,function) ->
    gs:config(Window#tfwindow.iconentry,{setfocus,true});
move_focus(Window,icon) ->
    gs:config(Window#tfwindow.messageentry,{setfocus,true});
move_focus(Window,message) ->
    gs:config(Window#tfwindow.htmlentry,{setfocus,true});
move_focus(Window,html) ->
    gs:config(Window#tfwindow.htmlentry,{setfocus,false});
move_focus(_Window,none) ->
    true.

%----------------------------------------
% display(Window,Text)
%   Window - tfwindow()
%   Text - string()
% Display a help message in the window
%----------------------------------------
display(Window,Text) ->
    gs:config(Window#tfwindow.label,{label,{text,Text}}).
    
%----------------------------------------
% display_clear(Window)
%   Window - tfwindow()
% Clear the help message display
%----------------------------------------
display_clear(Window) ->
    display(Window,"").

%----------------------------------------
% clear_info(Window)
%   Window - tfwindow()
% Clear the entries of Window (except the file entry)
%----------------------------------------
clear_info(Window) ->
    gs:config(Window#tfwindow.toolentry,{text,""}),
    gs:config(Window#tfwindow.moduleentry,{text,""}),
    gs:config(Window#tfwindow.functionentry,{text,""}),
    gs:config(Window#tfwindow.iconentry,{text,""}),
    gs:config(Window#tfwindow.messageentry,{text,""}),
    gs:config(Window#tfwindow.htmlentry,{text,""}).

%----------------------------------------
% show_info(Window,List)
%   Window - tfwindow()
%   List - [{Key,Val}]
%     Key - tool,     Val - string()
%     Key - start,    Val - {atom(),atom(),_}
%     Key - icon,     Val - string()
%     Key - message,  Val - string()
%     Key - html,     Val - string()
% Display the different Val's in the appropriate entries of Window
%----------------------------------------
show_info(_Window,[]) ->
    ok;
show_info(Window,[{tool,Tool}|Rest]) ->
    gs:config(Window#tfwindow.toolentry,{text,Tool}),
    show_info(Window,Rest);
show_info(Window,[{start,{M,F,_}}|Rest]) ->
    gs:config(Window#tfwindow.moduleentry,{text,M}),
    gs:config(Window#tfwindow.functionentry,{text,F}),
    show_info(Window,Rest);
show_info(Window,[{icon,Icon}|Rest]) ->
    gs:config(Window#tfwindow.iconentry,{text,Icon}),
    show_info(Window,Rest);
show_info(Window,[{message,Message}|Rest]) ->
    gs:config(Window#tfwindow.messageentry,{text,Message}),
    show_info(Window,Rest);
show_info(Window,[{html,Html}|Rest]) ->
    gs:config(Window#tfwindow.htmlentry,{text,Html}),
    show_info(Window,Rest).


%=============================================================================
% Retrieve user specified information
%=============================================================================
    
%----------------------------------------
% check_info(Window) => {ok,ToolInfo} | {error,Reason}
%   Window - tfwindow()
%   ToolInfo - toolinfo()
%   Reason - noname | nostart
% Check the information given in the entries and insert it into ToolInfo
% if all mandatory information is given.
%----------------------------------------
check_info(Window) ->

    %% First check mandatory elements: name and start function
    Tool = gs:read(Window#tfwindow.toolentry,text),
    M = gs:read(Window#tfwindow.moduleentry,text),
    F = gs:read(Window#tfwindow.functionentry,text),
    
    if
	Tool/="",M/="",F/="" ->
	    ToolInfo =
		#toolinfo{tool=Tool,
			  start={list_to_atom(M),list_to_atom(F),[]},
			  icon=gs:read(Window#tfwindow.iconentry,text),
			  message=gs:read(Window#tfwindow.messageentry,text),
			  html=gs:read(Window#tfwindow.htmlentry,text)},
	    {ok,ToolInfo};

	Tool=="" ->
	    {error,noname};
		
	true ->
	    {error,nostart}
    end.


%=============================================================================
% Save information to file
%=============================================================================

%----------------------------------------
% save_info(Win,File,ToolInfo) => ok | cancel | {error,waccess}
%   Win - GS object
%   File - string()
%   ToolInfo - toolinfo()
% Saves the information in ToolInfo to File on a predefined format.
%----------------------------------------
save_info(Win,File,ToolInfo) ->

    %% First check if file already exists
    case file:read_file_info(File) of
	{ok,_FileInfo} ->

	    %% Request the user to confirm that the file should
	    %% be overwritten
	    case tool_utils:confirm(Win,[File,
					 "exists, will be overwritten"]) of
		ok ->
		    save_info2(File,ToolInfo);
		cancel ->
		    cancel
	    end;

	{error,_Reason} -> % _Reason = "No such file or directory"
	    save_info2(File,ToolInfo)
    end.

%----------------------------------------
% save_info2(File,ToolInfo) => ok | {error,waccess}
%   File - string() File name
%   ToolInfo - toolinfo record
% Called by save_info/3
%----------------------------------------
save_info2(File,ToolInfo) ->
    case file:open(File, [write]) of
	{ok,Fd} ->
	    io:format(Fd,"{version,\"~s\"}.~n",[toolbar:version()]),
	    io:format(Fd,"{{tool,\"~s\"},~n",[ToolInfo#toolinfo.tool]),
	    io:format(Fd," {start,~w}",[ToolInfo#toolinfo.start]),
	    case ToolInfo#toolinfo.icon of
		"" -> ignore;
		Icon -> io:format(Fd,",~n {icon,\"~s\"}",[Icon])
	    end,
	    case ToolInfo#toolinfo.message of
		"" -> ignore;
		Message -> io:format(Fd,",~n {message,\"~s\"}",[Message])
	    end,
	    case ToolInfo#toolinfo.html of
		"" -> ignore;
		Html -> io:format(Fd,",~n {html,\"~s\"}",[Html])
	    end,
	    io:format(Fd,"}.~n",[]),
	    file:close(Fd),
	    ok;
	_Error ->
	    {error,waccess}
    end.


%=============================================================================
% Auxiliary functions
%=============================================================================

%----------------------------------------
% tool_file(File) => string()
%   File - string()
% Return a file name consisting of File with the suffix .tool added,
% if File does not already have this suffix.
%----------------------------------------
tool_file(File) ->
    case filename:extension(File) of
	".tool" -> File;
	_ -> File ++ ".tool"
    end.