%% ``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(tv_new_table).



-export([start/2,
	 init/3
	]).



-define(DEFAULT_BG_COLOR, {217, 217, 217}).
-define(FONT, {screen, 12}).

-define(WIN_WIDTH, 400).
-define(WIN_HEIGHT, 555).   %% 510

-define(FRAME_WIDTH, 400).
-define(FRAME1_HEIGHT, 170).
-define(FRAME2_HEIGHT, 260).
-define(FRAME3_HEIGHT, 125). %% 80
-define(BW, 2).

-define(FRAME_X, 0).
-define(FRAME1_Y, 0).
-define(FRAME2_Y, 170).
-define(FRAME3_Y, 430).


-define(LBL_HEIGHT, 30).
-define(NODE_LBL_WIDTH, 45).
-define(NAME_LBL_WIDTH, 85).
-define(TYPE_LBL_WIDTH, 45).
-define(PROT_LBL_WIDTH, 85).
-define(KEYPOS_LBL_WIDTH, 95).

-define(LBL_X, 10).
-define(NODE_LBL_Y, 20).
-define(NAME_LBL_Y, 80).
-define(TYPE_LBL_Y, 10).
-define(PROT_LBL_Y, 100).
-define(KEYPOS_LBL_Y, 200).


-define(ENTRY_HEIGHT, 30).
-define(NODE_ENTRY_WIDTH, 275).
-define(NAME_ENTRY_WIDTH, 275).
-define(KEYPOS_ENTRY_WIDTH, 50).

-define(ENTRY_X1, 110).
-define(ENTRY_X2, 110).
-define(NODE_ENTRY_Y, 20).
-define(NAME_ENTRY_Y, 80).
-define(KEYPOS_ENTRY_Y, 200).

-define(RBTN_HEIGHT, 30).
-define(RBTN_WIDTH1, 105).
-define(RBTN_WIDTH2, 115).

-define(RBTN_X1, 60).
-define(RBTN_X2, 165).
-define(RBTN_X3, 270).
-define(RBTN_Y1, 40).
-define(RBTN_Y1PLUS, 70).
-define(RBTN_Y2, 130).


-define(CBTN_HEIGHT, 30).
-define(NAMED_TABLE_CBTN_WIDTH, 100).
-define(OPEN_BROWSER_CBTN_WIDTH, 105).

-define(NAMED_TABLE_CBTN_X, 110).
-define(NAMED_TABLE_CBTN_Y, 120).

-define(OPEN_BROWSER_CBTN_X, 85).  %% 215
-define(OPEN_BROWSER_CBTN_Y, 10).  %% 200


-define(BTN_WIDTH, 100).
-define(BTN_HEIGHT, 30).

-define(BTN_X1, 85). 
-define(BTN_X2, 225).
-define(BTN_Y, 65).   %% 30


-define(VLINE_LBL_WIDTH, (380 - 2 * ?BW)).
-define(VLINE_LBL_HEIGHT, 1).
-define(HLINE_LBL_WIDTH, 1).
-define(HLINE_LBL_HEIGHT, 70).

-define(VLINE_LBL_X, (10 - ?BW)).
-define(VLINE_LBL_Y1, 85).
-define(VLINE_LBL_Y2, 180).
-define(HLINE_LBL_X, 188).
-define(HLINE_LBL_Y, 180).


-define(DEFAULT_NAME, my_table).
-define(DEFAULT_TYPE, set).
-define(DEFAULT_PROT, public).
-define(DEFAULT_KEYPOS, 1).




start(Node, ErrMsgMode) ->
    spawn_link(?MODULE, init, [Node, ErrMsgMode, self()]).





init(Node, ErrMsgMode, MPid) ->
    process_flag(trap_exit, true),
    put(error_msg_mode, ErrMsgMode),
    create_window(Node),
    loop(false, ?DEFAULT_TYPE, ?DEFAULT_PROT, true, MPid).





loop(NamedTab, Type, Prot, OpenBrowser, MPid) ->
    receive
	
	{gs, ok, click, _Data, _Args} ->
	    gs:config(win, [{cursor, busy}]),
	    case create_table(NamedTab, Type, Prot, OpenBrowser, MPid) of
		ok ->
		    exit(normal);
		error ->
		    gs:config(win, [{cursor, arrow}]),
		    loop(NamedTab, Type, Prot, OpenBrowser, MPid)
	    end;


	{gs, cancel, click, _Data, _Args} ->
	    exit(normal);


	{gs, set, click, _Data, _Args} ->
	    loop(NamedTab, set, Prot, OpenBrowser, MPid);


	{gs, ordered_set, click, _Data, _Args} ->
	    loop(NamedTab, ordered_set, Prot, OpenBrowser, MPid);


	{gs, bag, click, _Data, _Args} ->
	    loop(NamedTab, bag, Prot, OpenBrowser, MPid);


	{gs, duplicate_bag, click, _Data, _Args} ->
	    loop(NamedTab, duplicate_bag, Prot, OpenBrowser, MPid);


	{gs, public, click, _Data, _Args} ->
	    gs:config(open_browser, [{enable, true}, {select, OpenBrowser}]),
	    loop(NamedTab, Type, public, OpenBrowser, MPid);


	{gs, protected, click, _Data, _Args} ->
	    gs:config(open_browser, [{enable, true}, {select, OpenBrowser}]),
	    loop(NamedTab, Type, protected, OpenBrowser, MPid);

	
	{gs, private, click, _Data, _Args} ->
	    gs:config(open_browser, [{select, false}, {enable, false}]),
	    loop(NamedTab, Type, private, OpenBrowser, MPid);


	{gs, named_table, click, Data, _Args} ->
	    gs:config(named_table, [{data, not(Data)}]),
	    loop(Data, Type, Prot, OpenBrowser, MPid);
	    

	{gs, open_browser, click, Data, _Args} ->
	    gs:config(open_browser, [{data, not(Data)}]),
	    loop(Data, Type, Prot, Data, MPid);
	    

	{gs, EntryId, keypress, _Data, ['Tab', _No, 0 | _T]} ->
	    case get_entry_term(EntryId) of
		{ok, _Term} ->
		    gs:config(next_entry(EntryId, forward), [{setfocus, true},
							     {select, {0, 100000000}}]);
		error ->
		    done
	    end,
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);
	

	{gs, EntryId, keypress, _Data, ['Tab', _No, 1 | _T]} ->
	    case get_entry_term(EntryId) of
		{ok, _Term} ->
		    gs:config(next_entry(EntryId, backward), [{setfocus, true},
							      {select, {0, 100000000}}]);
		error ->
		    done
	    end,
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);
	

	{gs, EntryId, keypress, _Data, ['Down' | _T]} ->
	    case get_entry_term(EntryId) of
		{ok, _Term} ->
		    gs:config(next_entry(EntryId, forward), [{setfocus, true},
							     {select, {0, 100000000}}]);
		error ->
		    done
	    end,
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);
	

	{gs, EntryId, keypress, _Data, ['Up' | _T]} ->
	    case get_entry_term(EntryId) of
		{ok, _Term} ->
		    gs:config(next_entry(EntryId, backward), [{setfocus, true},
							      {select, {0, 100000000}}]);
		error ->
		    done
	    end,
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);
	

	{gs, _EntryId, keypress, _Data, ['Return' | _T]} ->
	    gs:config(win, [{cursor, busy}]),
	    case create_table(NamedTab, Type, Prot, OpenBrowser, MPid) of
		ok ->
		    exit(normal);
		error ->
		    gs:config(win, [{cursor, arrow}]),
		    loop(NamedTab, Type, Prot, OpenBrowser, MPid)
	    end;


	{gs, win, configure, _Data, _Args} ->
	    gs:config(win, [{width, ?WIN_WIDTH},
			    {height, ?WIN_HEIGHT}]),
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);

	
	{gs, win, destroy, _Data, _Args} ->
	    exit(normal);
	

	raise ->
	    gs:config(win, [raise]),
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);	    


	{error_msg_mode, ErrMsgMode} ->
	    put(error_msg_mode, ErrMsgMode),
	    loop(NamedTab, Type, Prot, OpenBrowser, MPid);
	

	{'EXIT', _Pid, _Reason} ->
	    exit(normal);


	_Other ->
    	    loop(NamedTab, Type, Prot, OpenBrowser, MPid)
    
    end.




create_table(NamedTab, Type, Prot, OpenBrowser, MPid) ->
    case get_entry_term(node_entry) of
	error ->
	    error;
	{ok, Node} ->
	    case get_entry_term(name_entry) of
		error ->
		    error;
		{ok, TabName} ->
		    case get_entry_term(keypos_entry) of
			error ->
			    error;
			{ok, KeyPos} ->
			    Options = 
				[Type, Prot, {keypos, KeyPos}] ++
				case NamedTab of
				    true ->
					[named_table];
				    false ->
					[]
				end,
			    {Readable, NewOpenBrowser} = 
				case Prot of
				    private ->
					{false, false};
				    _Other ->
					{true, OpenBrowser}
				end,
			    MPid ! {tv_new_table, self(), Node, TabName, Options, ets,
				    Readable, NewOpenBrowser},
			    receive
				ok ->
				    ok;
				error ->
				    show_error_msg(),
				    error
			    after 
				5000 ->
				    show_error_msg(),
				    error
			    end
		    end
	    end
    end.





show_error_msg() ->
    Msg = 
	case get(error_msg_mode) of
	    normal ->
		["Couldn't create a table using",
		 "the specified settings!"];
	    haiku ->
		["The table you want",
		 "Could maybe be created.",
		 "But I don't know how."]
	end,
    tv_utils:notify(win, "TV Notification", Msg).

    





get_entry_term(Id) ->
    EditedStr = gs:read(Id, text),
    case tv_db_search:string_to_term(EditedStr) of
	{ok, NewTerm} when Id == node_entry, atom(NewTerm) ->
	    {ok,NewTerm};
	{ok, NewTerm} when Id == name_entry, atom(NewTerm) ->
	    {ok,NewTerm};
	{ok, NewTerm} when Id == keypos_entry, integer(NewTerm), NewTerm > 0 ->
	    {ok,NewTerm};
	_Other ->
	    NewMsg =
		case get(error_msg_mode) of
		    normal ->
			case Id of
			    node_entry ->
				["Please enter a valid node name!"];
			    name_entry ->
				["Please enter a valid table name!"];
			    keypos_entry ->
				["Please enter a valid key position!"]
			end;
		    haiku ->
			E1 = "Aborted effort",
			L  =
			    case Id of 
				node_entry ->
				    ["Reflect, repent and retype:",
				     "Enter valid node."];
				name_entry ->
				    ["Reflect, repent and retype:",
				     "Enter valid name."];
				keypos_entry ->
				    ["Reflect, repent and retype",
				     "Key position, please."]
			    end,
			[E1 | L]
		end,
	    gs:config(Id, [beep, {select, {0, 100000000}}, {setfocus, true}]),
	    tv_utils:notify(win, "TV Notification", NewMsg),
	    error
    end.


    


next_entry(node_entry, forward) ->
    name_entry;
next_entry(node_entry, backward) ->
    keypos_entry;
next_entry(name_entry, forward) ->
    keypos_entry;
next_entry(name_entry, backward) ->
    node_entry;
next_entry(keypos_entry, forward) ->
    node_entry;
next_entry(keypos_entry, backward) ->
    name_entry.




create_window(Node) ->
    gs:window(win, gs:start(), [{width, ?WIN_WIDTH},
				{height, ?WIN_HEIGHT},
				{bg, ?DEFAULT_BG_COLOR},
				{title, "[TV]   Create New ETS Table"},
				{configure, true},
				{destroy, true},
				{cursor, arrow}
			       ]),
    
    gs:frame(frame1, win, [{width, ?FRAME_WIDTH},
			   {height, ?FRAME1_HEIGHT},
			   {x, ?FRAME_X},
			   {y, ?FRAME1_Y},
			   {bg, ?DEFAULT_BG_COLOR},
			   {bw, ?BW}]),
    gs:frame(frame2, win, [{width, ?FRAME_WIDTH},
			   {height, ?FRAME2_HEIGHT},
			   {x, ?FRAME_X},
			   {y, ?FRAME2_Y},
			   {bg, ?DEFAULT_BG_COLOR},
			   {bw, ?BW}]),
    gs:frame(frame3, win, [{width, ?FRAME_WIDTH},
			   {height, ?FRAME3_HEIGHT},
			   {x, ?FRAME_X},
			   {y, ?FRAME3_Y},
			   {bg, ?DEFAULT_BG_COLOR},
			   {bw, ?BW}]),

    gs:label(frame1, [{width, ?NODE_LBL_WIDTH},
		      {height, ?LBL_HEIGHT},
		      {x, ?LBL_X},
		      {y, ?NODE_LBL_Y},
		      {bg, ?DEFAULT_BG_COLOR},
		      {fg, {0,0,0}},
		      {align, w},
		      {font, ?FONT},
		      {label, {text, "Node:"}}
		     ]),
    gs:label(frame1, [{width, ?NAME_LBL_WIDTH},
		      {height, ?LBL_HEIGHT},
		      {x, ?LBL_X},
		      {y, ?NAME_LBL_Y},
		      {bg, ?DEFAULT_BG_COLOR},
		      {fg, {0,0,0}},
		      {align, w},
		      {font, ?FONT},
		      {label, {text, "Table name:"}}
		     ]),
    gs:label(frame2, [{width, ?TYPE_LBL_WIDTH},
		      {height, ?LBL_HEIGHT},
		      {x, ?LBL_X},
		      {y, ?TYPE_LBL_Y},
		      {bg, ?DEFAULT_BG_COLOR},
		      {fg, {0,0,0}},
		      {align, w},
		      {font, ?FONT},
		      {label, {text, "Type:"}}
		     ]),
    gs:label(frame2, [{width, ?PROT_LBL_WIDTH},
		      {height, ?LBL_HEIGHT},
		      {x, ?LBL_X},
		      {y, ?PROT_LBL_Y},
		      {bg, ?DEFAULT_BG_COLOR},
		      {fg, {0,0,0}},
		      {align, w},
		      {font, ?FONT},
		      {label, {text, "Protection:"}}
		     ]),
    gs:label(frame2, [{width, ?KEYPOS_LBL_WIDTH},
		      {height, ?LBL_HEIGHT},
		      {x, ?LBL_X},
		      {y, ?KEYPOS_LBL_Y},
		      {bg, ?DEFAULT_BG_COLOR},
		      {fg, {0,0,0}},
		      {align, w},
		      {font, ?FONT},
		      {label, {text, "Key position:"}}
		     ]),
        
    gs:entry(node_entry, frame1, [{width, ?NODE_ENTRY_WIDTH},
				  {height, ?ENTRY_HEIGHT},
				  {x, ?ENTRY_X1},
				  {y, ?NODE_ENTRY_Y},
				  {bg, {255,255,255}},
				  {fg, {0,0,0}},
				  {font, ?FONT},
				  {enable, true},
				  {text, "'" ++ atom_to_list(Node) ++ "'"},
				  {keypress, true}
				 ]),
    gs:entry(name_entry, frame1, [{width, ?NAME_ENTRY_WIDTH},
				  {height, ?ENTRY_HEIGHT},
				  {x, ?ENTRY_X1},
				  {y, ?NAME_ENTRY_Y},
				  {bg, {255,255,255}},
				  {fg, {0,0,0}},
				  {font, ?FONT},
				  {enable, true},
				  {text, atom_to_list(?DEFAULT_NAME)},
				  {keypress, true},
				  {setfocus, true},
				  {select, {0,100000000}}
				 ]),
    gs:entry(keypos_entry, frame2, [{width, ?KEYPOS_ENTRY_WIDTH},
				    {height, ?ENTRY_HEIGHT},
				    {x, ?ENTRY_X2},
				    {y, ?KEYPOS_ENTRY_Y},
				    {bg, {255,255,255}},
				    {fg, {0,0,0}},
				    {font, ?FONT},
				    {enable, true},
				    {keypress, true},
				    {text, integer_to_list(?DEFAULT_KEYPOS)}
				   ]),
    
    gs:radiobutton(set, frame2, [{width, ?RBTN_WIDTH1},
				 {height, ?RBTN_HEIGHT},
				 {x, ?RBTN_X1},
				 {y, ?RBTN_Y1},
				 {align, w},
				 {label, {text, "set"}},
				 {group, type}
				 ]),
    gs:radiobutton(ordered_set, frame2, [{width, ?RBTN_WIDTH1},
					 {height, ?RBTN_HEIGHT},
					 {x, ?RBTN_X2},
					 {y, ?RBTN_Y1},
					 {align, w},
					 {label, {text, "ordered_set"}},
					 {group, type}
					]),
    gs:radiobutton(bag, frame2, [{width, ?RBTN_WIDTH1},
				 {height, ?RBTN_HEIGHT},
				 {x, ?RBTN_X1},
				 {y, ?RBTN_Y1PLUS},
				 {align, w},
				 {label, {text, "bag"}},
				 {group, type}
				 ]),
    gs:radiobutton(duplicate_bag, frame2, [{width, ?RBTN_WIDTH2},
					   {height, ?RBTN_HEIGHT},
					   {x, ?RBTN_X2},
					   {y, ?RBTN_Y1PLUS},
					   {align, w},
					   {label, {text, "duplicate_bag"}},
					   {group, type}
					  ]),
    
    gs:radiobutton(public, frame2, [{width, ?RBTN_WIDTH1},
				    {height, ?RBTN_HEIGHT},
				    {x, ?RBTN_X1},
				    {y, ?RBTN_Y2},
				    {align, w},
				    {label, {text, "public"}},
				    {group, protection}
				   ]),
    gs:radiobutton(protected, frame2, [{width, ?RBTN_WIDTH1},
				       {height, ?RBTN_HEIGHT},
				       {x, ?RBTN_X2},
				       {y, ?RBTN_Y2},
				       {align, w},
				       {label, {text, "protected"}},
				       {group, protection}
				      ]),
    gs:radiobutton(private, frame2, [{width, ?RBTN_WIDTH2},
				     {height, ?RBTN_HEIGHT},
				     {x, ?RBTN_X3},
				     {y, ?RBTN_Y2},
				     {align, w},
				     {label, {text, "private"}},
				     {group, protection}
				    ]),
    
    gs:checkbutton(named_table, frame1, [{width, ?NAMED_TABLE_CBTN_WIDTH},
					 {height, ?CBTN_HEIGHT},
					 {x, ?NAMED_TABLE_CBTN_X},
					 {y, ?NAMED_TABLE_CBTN_Y},
					 {align, w},
					 {label, {text, "Named table"}},
					 {select, false},
					 {data, true}
					]),

    gs:checkbutton(open_browser, frame3, [{width, ?OPEN_BROWSER_CBTN_WIDTH},
					  {height, ?CBTN_HEIGHT},
					  {x, ?OPEN_BROWSER_CBTN_X},
					  {y, ?OPEN_BROWSER_CBTN_Y},
					  {align, w},
					  {label, {text, "Open browser"}},
					  {select, true},
					  {data, false}
					 ]),

%%    gs:label(frame2, [{width, ?VLINE_LBL_WIDTH},
%%		      {height, ?VLINE_LBL_HEIGHT},
%%		      {x, ?VLINE_LBL_X},
%%		      {y, ?VLINE_LBL_Y1},
%%		      {bg, {0,0,0}}
%%		     ]),
%%    gs:label(frame2, [{width, ?VLINE_LBL_WIDTH},
%%		      {height, ?VLINE_LBL_HEIGHT},
%%		      {x, ?VLINE_LBL_X},
%%		      {y, ?VLINE_LBL_Y2},
%%		      {bg, {0,0,0}}
%%		     ]),
%%    gs:label(frame2, [{width, ?HLINE_LBL_WIDTH},
%%		      {height, ?HLINE_LBL_HEIGHT},
%%		      {x, ?HLINE_LBL_X},
%%		      {y, ?HLINE_LBL_Y},
%%		      {bg, {0,0,0}}
%%		     ]),
%%    
    gs:button(ok, frame3, [{width, ?BTN_WIDTH},
			   {height, ?BTN_HEIGHT},
			   {x, ?BTN_X1},
			   {y, ?BTN_Y},
			   {bg, ?DEFAULT_BG_COLOR},
			   {fg, {0,0,0}},
			   {label, {text, "OK"}}
			  ]),
    gs:button(cancel, frame3, [{width, ?BTN_WIDTH},
			       {height, ?BTN_HEIGHT},
			       {x, ?BTN_X2},
			       {y, ?BTN_Y},
			       {bg, ?DEFAULT_BG_COLOR},
			       {fg, {0,0,0}},
			       {label, {text, "Cancel"}}
			      ]),

    gs:config(?DEFAULT_TYPE, [{select, true}]),
    gs:config(?DEFAULT_PROT, [{select, true}]),
    
    gs:config(win, [{map, true}]).
    






