%%
%% %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%
%%

%%
%% ------------------------------------------------------------
%% File Selection Dialog
%% ------------------------------------------------------------

-module(file_dialog).
-compile([{nowarn_deprecated_function,{gs,config,2}},
          {nowarn_deprecated_function,{gs,create,4}},
          {nowarn_deprecated_function,{gs,label,2}},
          {nowarn_deprecated_function,{gs,read,2}},
          {nowarn_deprecated_function,{gs,start,0}}]).

-export([start/0,start/1,start/2,fs_init/3]).

-include_lib("kernel/include/file.hrl").


%% ----- File Selection ----
start() ->
    {ok,Dir}=file:get_cwd(),
    start(Dir,[]).

start(Dir) ->
    start(Dir,[]).

start(Dir,File) ->
    Dir0 = case lists:last(Dir) of
	$/ -> Dir;
	_  -> lists:append(Dir,"/")
    end,
    Pid=spawn(file_dialog,fs_init,[Dir0,File,self()]),	
    receive
	{file_dialog,Pid,Result} -> Result
    end.


%% ------------------------------------------------------------
fs_init(Dir,File,Owner) ->
    S=gs:start(),
    gs:create(window,win,S,[{width,250},{height,265},{title,"File Dialog"},
			    {configure,true}]),
    gs:create(label,label,win,[{y,0},{width,250},{label, {text,Dir}}]),
    gs:label(win,[{width,50},{y,30},{x,5},{label, {text,"File:"}}]),
    gs:create(entry,entry,win,[{y,30},{width,190},{x,55},
			{keypress,true},{focus,true}]),
    gs:create(listbox,lb,win,[{x,5},{y,60},{width,160},{height,199},
			   {vscroll,right},{click,true},{doubleclick,true}]),
    gs:create(button,ok,win,[{label, {text,"OK"}},{width,40},{x,185},{y,170}]),
    gs:create(button,cancel,win,[{label, {text,"Cancel"}},{x,175},{y,220},{width,65}]),
    Items=refresh(Dir),
    %% --- select File if it's given ---
    case index_member(File,Items) of
	{ok,Index} ->
	    gs:config(lb,{selection,clear}),
	    gs:config(lb,{selection,Index});
	_ -> true
    end,
    gs:config(win,{map,true}),
    fs_loop(Dir,Owner).

fs_loop(Dir,Owner) ->
    receive
	{gs,ok,click,_,_} ->
	    entered_name(Dir,Owner);
	{gs,cancel,click,_,_} ->
	    Owner ! {file_dialog,self(),cancel};
	{gs,entry,keypress,_,['Return'|_]} ->
	    entered_name(Dir,Owner);
	{gs,entry,keypress,_,[_Keysym|_]} ->
	    fs_loop(Dir,Owner);
	{gs,lb,click,_,_} ->
	    clicked(Dir,Owner);
	{gs,lb,doubleclick,_,_} ->
	    double_clicked(Dir,Owner);
	{gs,win,configure,_,[250,265|_]} -> % already got that size
	    fs_loop(Dir,Owner);
	{gs,win,configure,_,_} ->
	    gs:config(win,[{geometry,{250,265}}]),
	    fs_loop(Dir,Owner);
	stop ->
	    exit(normal);
	{gs,_,destroy,_,_} -> 
	    Owner ! {file_dialog,self(),cancel};
	X ->
	    io:format("file_dialog: got other: ~w.~n",[X]),
	    fs_loop(Dir,Owner)
    end.



refresh(Dir) ->
    gs:config(lb,clear),
    gs:config(label,{label, {text,Dir}}),
    gs:config(entry,{text,""}),
    Items=["../"|get_files(Dir)],
    gs:config(lb,[{items,Items}]),
    Items.

    
entered_name(Dir,Owner) ->
    File=gs:read(entry,text),
    case check_file(Dir,File) of
	{file,Dir2,File2} ->
	    Owner ! {file_dialog,self(),{ok,Dir2,File2}};
	{dir,Dir2} ->
	    refresh(Dir2),
	    fs_loop(Dir2,Owner);
	{error,no_file} ->
	    double_clicked(Dir,Owner);
	_ ->
	    fs_loop(Dir,Owner)
    end.


clicked(Dir,Owner) ->
    [Idx|_]=gs:read(lb,selection),
    File=gs:read(lb,{get,Idx}),
    case lists:last(File) of
	$/ -> %it's a dir
	    true;
	_ -> % it's a file
	    gs:config(entry,{text,File})
    end,
    fs_loop(Dir,Owner).


double_clicked(Dir,Owner) ->
    case gs:read(lb,selection) of
	[0] -> % up one dir
	    NewDir=up_one_dir(Dir),
	    refresh(NewDir),
	    fs_loop(NewDir,Owner);
	[] ->
	    fs_loop(Dir,Owner);
	[Idx] ->
	    File=gs:read(lb,{get,Idx}),
	    case lists:last(File) of
		$/ -> % down a dir
		    NewDir=lists:append(Dir,File),
		    refresh(NewDir),
		    fs_loop(NewDir,Owner);
		_ -> % done
		    Owner!{file_dialog,self(),{ok,Dir,File}}
	    end
    end.


%% checks if a file exists
%% returns {file,Dir,File}
%%         {dir,Dir}
%%    or   {error,What}
check_file(Dir,File) ->
    case catch lists:last(File) of
	$/ -> % File is a Dir
	    NewDir = case File of
			 [$/|_] -> %absolute path
			     File;
			 _ -> %relative path
			     lists:append(Dir,File)
	    end,
	    case file:list_dir(NewDir) of
		{ok,_} -> {dir,NewDir};
		_      -> {error,bad_dir}
	    end;
	{'EXIT',_Why} -> {error,no_file};
	_ ->
	    Words=string:tokens(File,[$/,$\\]),
	    NewFile=lists:last(Words),
	    NewDir = case File of
		[$/|_] -> %absolute path
		    up_one_dir(File);
		_ -> %relative path
		    case up_one_dir(File) of
			[$/]        -> Dir;
			[$/|SubDir] -> lists:flatten([Dir,SubDir,$/])
		    end
	    end,
	    case file:read_file_info(lists:append(NewDir,NewFile)) of
		{ok,_} -> 
		    {file,NewDir,NewFile};
		_ -> 
		    {error,bad_file}
	    end
    end.

	        
get_files(Dir) -> 
    {ok,Files} = file:list_dir(Dir),
    add_slash(Dir,lists:sort(Files)).
 
add_slash(_,[]) -> [];
add_slash(Dir,[H|T]) ->
    case file:read_file_info(lists:append(Dir,[$/|H])) of
	{ok,FI} when FI#file_info.type==directory ->
            [lists:append(H,"/")|add_slash(Dir,T)];
        _ ->
	    [H|add_slash(Dir,T)]
    end.


%filter([H|T]) ->
%    case lists:last(H) of
%	$/ -> [H|filter(T)];
%	_ ->
%	    Len =length(H),
%	    if Len>4 ->
%		    case lists:nthtail(Len-4,H) of
%			".erl" -> [H|filter(T)];
%			_ -> filter(T)
%		    end;
%		true -> filter(T)
%	    end
%    end;
%filter([]) ->    
%    [].
	
    
%% like member but also returns index
index_member(Item,List) ->
    i_m(0,Item,List).

i_m(N,Item,[Item|_List]) ->
    {ok,N};
i_m(N,Item,[_|List]) ->
    i_m(N+1,Item,List);
i_m(_N,_Item,[]) ->
    false.

up_one_dir(Dir) ->
    L =string:tokens(Dir,[$/,$\\]),
    lists:flatten(rem_last(L)).

rem_last([_Last]) ->
    [$/];
rem_last([Head|Tail]) ->
    [$/,Head|rem_last(Tail)];
rem_last([]) ->
    [$/].
		  
%% ----------------------------------------
%% done