%%
%% %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%
%%------------------------------------------------------------
%%
%% Simple text viewer
%%
%%------------------------------------------------------------

-module(appmon_txt).
-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,1}}]).
-export([start/0, start/1, print/1, fprint/1]).

%% gen_server stuff
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2]).

-define(LOADTXT, "Load file").
-define(SAVETXT, "Save file").
-define(SAVEASTXT, "Save as").
-define(CLOSETXT, "Close").
-define(HELPTXT, "Help").

%%------------------------------------------------------------
%%
%% start/0 starts an open text viewer that can be filled with
%% whatever.
%%
%%------------------------------------------------------------
start() ->
    start([]).

%%------------------------------------------------------------
%%
%% start(ListOfOptions) starts an open text viewer with options
%%
%% Options can be
%% {file, FileName}	- insert contents of file
%% locked		- the text cannot be edited
%% {text, Text}		- insert text at startup
%%
%%------------------------------------------------------------
start(Opts) ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []).

%% Start a text viewer if necessary
print(Txt) ->
    catch start(),
    gen_server:call(?MODULE, {add_txt, Txt}),
    ok.

fprint(File) ->
    catch start(),
    gen_server:call(?MODULE, {add_file, File}),
    ok.


%%------------------------------------------------------------
%% gen server admin

init(Opts) ->
    process_flag(trap_exit, true),
    setup_base_win(),
    default_status(),
    setup_opts(Opts),
    {ok, []}.

terminate(_Reason, _State) ->
    ok.

%%------------------------------------------------------------
%% gen server stuff
handle_call({add_txt, Txt}, _From, State) ->
    do_insert_text(Txt),
    scroll_to_last_line(),
    {reply, ok, State};
handle_call({add_file, FileName}, _From, State) ->
    do_load_file(FileName),
    {reply, ok, State};
handle_call(_Request, _From, State) ->
    {reply, ok, State}.
handle_cast(_Request, State) ->
    {noreply, State}.
handle_info({gs, _, click, _, [?CLOSETXT|_]}, State) ->
    {stop, normal, State};
handle_info({gs, _, click, _, [?LOADTXT|_]}, State) ->
    ui_load(),
    {noreply, State};
handle_info({gs, _, configure, _, [W, H | _]}, State) ->
    resize(W, H),
    {noreply, State};

handle_info({gs, _, destroy, _, _}, State) ->
    {stop, normal, State};
handle_info(Request, State) ->
    io:format("~p got info: ~p~n", [self(), Request]),
    print_status("Not implemented"),
    {noreply, State}.


%%------------------------------------------------------------
%% Handle options

setup_opts([Opt|Opts]) -> 
    setup_opt(Opt),
    setup_opts(Opts);
setup_opts([]) -> ok.

setup_opt(Opt) ->
    case Opt of
	{file, FileName} ->
	    do_load_file(FileName);
	locked ->
	    do_lock();
	{text, Text} ->
	    do_insert_text(Text);
	_Other ->
	    ok
    end.

do_load_file(FileName) ->
    case catch i_load_file(FileName) of
	ok ->
	    default_status();
	_Other -> 
	    print_status(lists:append(["File not found: ", FileName]))
    end.

i_load_file(FileName) ->
    {ok, Bin} = file:read_file(FileName),
    L = binary_to_list(Bin),
    i_do_clear(),
    do_insert_text(L),
    ok.

ui_load() ->
    Title = "Load file",
    Files = get_file_list(),
    case catch ui_list_dialog(Title, "File: ", Files) of
	{ok, FileName} ->
	    do_load_file(FileName);
	_Other ->
	    print_status("Load cancelled")
    end.

get_file_list() ->
    case file:list_dir(".") of
	{ok, FileList} -> lists:sort(FileList);
	_Other -> []
    end.

do_insert_text(Text) ->
    gs:config(editor(), {insert, {'end', Text}}),
    ok.

%% Scrolls editor to show the last rows
scroll_to_last_line() ->
    H = gs:read(editor(), size),
    R = gs:read(editor(), height),
    TopRow = H-R/15,
    if  TopRow > 0 -> gs:config(editor(), {vscrollpos, TopRow});
	true       -> gs:config(editor(), {vscrollpos, 0})
	end,
    ok.

do_lock() ->    
    gs:config(editor(), {enable, false}).

i_do_clear() ->
    gs:config(editor(), clear).

%%------------------------------------------------------------
%% Graphical stuff

label_h() -> 20.
menu_h() -> 29.

setup_base_win() ->
    H = 400, W=580,
    LabelHeight=label_h(), MenuHeight=menu_h(),

    F = gs:start([{kernel,true}]),
    set_winroot(F),

    Win = gs:create(window, F, [{width, W}, {height, H}, 
				{title,"APPMON: Process Information"}]),

    E = gs:create(editor, Win, [{x, 0}, {y, MenuHeight}, 
				{width, W}, 
				{height, H-MenuHeight-LabelHeight-1}, 
				{vscroll, right}]),
    set_editor(E),

    L = gs:create(label, Win, [{x, 0}, {y, H-LabelHeight}, 
			       {height,LabelHeight }, {width, W}, 
			       {align, w}]),
    set_status(L),
    print_status("Loading"),

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

    MB = gs:create(menubar, Win, []),

    FMB = gs:create(menubutton, MB, [{label, {text, "File"}}]),
    FM = gs:create(menu, FMB, []),
    gs:create(menuitem, FM, [{label, {text, ?CLOSETXT}}]),

    gs:config(Win, {configure, true}),
    ok.

resize(W, H) ->
    gs:config(editor(), [{width, W}, {height, H-label_h()-menu_h()}]),
    gs:config(status(), [{y, H-label_h()}, {width, W}]),
    ok.

%%------------------------------------------------------------
%% ui_list_dialog(
%%
%%	Traditional dialog with a list box and a selection field that
%%	is updated from the list box.
%%
%%	Returns {ok, String} if successful and something else if not
%%
%%	Title - the name of the window
%%	LeadText - the lead text on the selection field
%%	List - a list of items that will be displayed in the list box
%%
%%------------------------------------------------------------

ui_list_dialog(Title, LeadText, TxtList) ->
    W = 200, H = 300,
    
    Win = gs:create(window, winroot(), [{title, Title}, 
					{width, W},{height, H}]),
    Ok = gs:create(button, Win, [{x, 10}, {y,10},
				 {width, 50}, {height, 20},
				 {label, {text, "Ok"}}]),
    Cn = gs:create(button, Win, [{x, 70}, {y,10},
				 {width, 50}, {height, 20},
				 {label, {text, "Cancel"}}]),

    gs:create(label, Win, [{x, 10}, {y, 50},
			   {width, 60}, {height, 20},
			   {label, {text, LeadText}}]),
    Box = gs:create(entry, Win, [{x, 10}, {y, 70},
				 {width, 160}, {height, 20},
				 {keypress, true}]),
    List = gs:create(listbox, Win, [{x, 10}, {y, 100}, {width, 180}, 
				    {height, 190},
				    {items, TxtList}, {vscroll, right},
				    {hscroll, false}, {click, true},
				    {doubleclick, true},
				    {keypress, true}]),
    gs:config(Win, {map, true}),

    RetVal = ui_load_loop(Box, List, Ok, Cn),

    gs:destroy(Win),
    
    RetVal.

ui_load_loop(Box, List, Ok, Cn) ->    
    receive
	{gs, Box, keypress, _, ['Return'|_]} ->
	    {ok, gs:read(Box, text)};
	{gs, Box, keypress, _, _} ->
	    ui_load_loop(Box, List, Ok, Cn);
	{gs, Ok, click, _, _} ->
	    {ok, gs:read(Box, text)};
	{gs, List, doubleclick, _, [_Idx, Txt|_]} ->
	    {ok, Txt};
	{gs, List, click, _, [_Idx, Txt|_]} ->
	    gs:config(Box, {text, Txt}),
	    ui_load_loop(Box, List, Ok, Cn);
	_Other -> 
	    something_else
    end.

%% The status row at the bottom of the window
set_status(Id) -> put(status_row, Id).
status() -> get(status_row).
print_status(Msg) -> gs:config(get(status_row), {label, {text, Msg}}).
default_status() -> print_status("Done").

set_editor(X) -> put(editor, X).
editor() -> get(editor).

winroot() -> get(winroot).
set_winroot(X) -> put(winroot, X).
