################################################################################
# TSL-LIBRARY:	EMOS_STD_menue_lib
################################################################################
# Copyright (C) 2000  EMOS Computer Consulting GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# For further information please contact:
#
#	Dean Rajovic
#	EMOS Computer Consulting GmbH
#	Oskar-Messter-Straße 25
#	85737 Ismaning
#	Germany
#	tel.: +49 89 608 765-0
#	mailto:drajovic@emos.de
#	http://www.emos.de
################################################################################
# $Revision: 1.1.1.1 $
# $Author: drajovic $
# $Date: 2004/03/24 20:14:03 $
# $Archive: /MERCURY/TSL_PROJECTS/EMOS_GPL/STD/emos_std_menue_lib/script $
# $NoKeywords: $
################################################################################

#**#
#*	This library contains alternative implementations for standard functions
#*	that operate on menues (menu_x() functions).
#*	Another sort of functions in this library are functions that implement some
#*	additional functionality that would probably fit into Mercury's logic
#*	for menu_x() functions.
#*/

static const COMPLETE_PATH = 1;
static const LAST_ENTRY = 2;

static menu_selection_mode = LAST_ENTRY;

#**
#*	Call this function to cause menu_select_item to select the complete menu path.
#*  <p>Note:<br>
#*  Behaves the same as WinRunner, the only problem is that it does not always work.
#*/

public function EMOS_menu_set_complete_path_selection()
{
    menu_selection_mode = COMPLETE_PATH;
}

#**
#*	Call this function to cause menu_select_item to select only the last item
#*  instead of the complete menu path.
#*  <p>Example:<br>
#*     instead of calling menu_select_item( "aaa;bbb;ccc" )<br>
#*     this mode causes menu_select_item( "ccc" ) to be called
#*  <p>Note:<br>
#*  This is the default mode.<br>
#*  It uses an undocumented feature of WR that appears to work more often than
#*  the documented one.
#*/

public function EMOS_menu_set_last_entry_selection()
{
    menu_selection_mode = LAST_ENTRY;
}

#**
#*	Returns TRUE if COMPLETE_PATH selection is activated.
#* @return TRUE if COMPLETE_PATH selection FALSE otherwise
#*/

public function EMOS_menu_is_complete_path_selection()
{
    return (menu_selection_mode == COMPLETE_PATH) ? TRUE : FALSE;
}

#**
#*	Returns TRUE if LAST_ENTRY selection is activated.
#* @return TRUE if LAST_ENTRY selection FALSE otherwise
#*/

public function EMOS_menu_is_last_entry_selection()
{
    return (menu_selection_mode == LAST_ENTRY) ? TRUE : FALSE;
}

#**
#*	This function is specially designed for a particular DOS application. This
#*	application has its own representation of a menu bar. WinRunner is capable
#*	of recognising text within the menu bar.
#*	This function clicks on a particular string (item) within the menu bar.
#*<p> NOTE!
#*	Please note that position and size of the menu bar is hard-coded.
#* @param win (in)	name of the window that contains the menu bar
#* @param item (in)	the string to be selected
#* @return
#*	E_OK:	Success
#*	!E_OK:	Error
#*/

public function DOS_menu_select_item( in win, in item )
{
	auto rc, arr[], i;
	rc=win_find_text( win, item, arr, 5, 23, 1024, 45, TRUE );
	if ( rc != E_OK )
		return rc;
	return win_mouse_click( win, arr[1], arr[2]-23 );
}

#**
#* This function clicks on a menu item without requiring items to be learned.
#* @param item the item to be selected
#* @param win [optional] window where actions are to be performed
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/
public function EMOS_menu_select_item1 ( in item, in win )
{
	auto dummy;
	return EMOS_menu_item ( "sel", item, dummy, dummy, dummy, dummy, win );
}

#**
#* This function returns the info of a menu item without requiring items to be learned.
#* @param item the item to be selected
#* @param attr attribute to be examined
#* @param info (out) info retrieved
#* @param win [optional] window where actions are to be performed
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/
public function EMOS_menu_get_info1 ( in item, in attr, out info, in win )
{
	auto dummy;
	return EMOS_menu_item ( "get", item, attr, dummy, info, dummy, win );
}

#**
#* This function waits for the info of a menu item without requiring items to be learned.
#* @param item the item to be selected
#* @param attr attribute to be examined
#* @param info info to be waited for
#* @param time [optional] time to be waited for
#* @param win [optional] window where actions are to be performed
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/
public function EMOS_menu_wait_info1 ( in item, in attr, in info, in time, in win )
{
	auto dummy;
	return EMOS_menu_item ( "wait", item, attr, info, dummy, time, win );
}

#**
#* This function compares the expected with the actual info of a menu item without requiring items to be learned.
#* @param item the item to be selected
#* @param attr attribute to be examined
#* @param info info to be checked
#* @param win [optional] window where actions are to be performed
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/
public function EMOS_menu_check_info1 ( in item, in attr, in info, in win )
{
	auto dummy;
	return EMOS_menu_item ( "chk", item, attr, info, dummy, dummy, win );
}

#**
#* This function implements the actual logic for processing menu items that are not in the GUI-map.
#* @param action action to be performed
#* @param item the item to be selected
#* @param attr [optional] attribute to be examined
#* @param inInfo [optional] info to be used
#* @param outInfo (out) [optional] info to be returned
#* @param time [optional] time to be waited for
#* @param win [optional] window where actions are to be performed
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/

static function EMOS_menu_item ( in action, in item, in attr, in inInfo, out outInfo, in time, in window )
{
	static const SEP = ";";
	static const MENWIN = "EMOS_menu_win";
	static const MENFILE = getenv( "TMP" ) & "\\" & "EMOSmenu";
	auto win = (window == "") ? GUI_get_window() : window;

	auto arr[], count, i;
	auto descr, desc, info;
	auto item_i, item_n;
	auto rc;
	
	count = split( item, arr, SEP );
	if ( count < 1 )
		return E_ILLEGAL_PARAMETER;

	# create & load a temporary GUI-file
	rc =GUI_close( MENFILE );
	rc+=GUI_buf_new( MENFILE );
	rc+=GUI_load( MENFILE );
	rc+=GUI_map_get_desc ( win, "", descr, info );
	rc+=GUI_add( MENFILE, MENWIN, "", descr );
	if ( rc != E_OK )
		return rc;

	# create the temporary item(s) using names 1;2;...
	for ( i=1; i<count+1; i++ )
	{
		item_i = ( i == 1  ? i : item_i & SEP & i );
		item_n = ( i == 1 ? arr[i] : item_n & SEP & arr[i] );
		if ( match( arr[i], "#[0-9][0-9]*" ) == 1 )
		{
			desc = sprintf( "{ class: menu_item, parent: %s, position: %d }"
						, (i==1 ? "none" : i-1)
						, substr(arr[i], 2)-1 ); # position has offset 0
		}
		else
		{
			desc = sprintf( "{ class: menu_item, parent: %s, label: \"%s\" }"
						, (i==1 ? "none" : i-1)
						, arr[i] );
		}
		rc+=GUI_add( MENFILE, MENWIN, i, desc );
	}
	if ( rc != E_OK )
	{
		GUI_close( MENFILE );
		return rc;
	}
	# perform the selection
	rc+=set_window( MENWIN );

    # watch this trick
    # menu_select_item() is unreliable in its documented form which says
    # that subitems must be comma-separated (e.g. menu_select_item( "File;New..." );
    # It appears that menu_select_item( "New..." ) not only works but it is also more reliable.
    # Here we decide what entry is going to be used

    if ( EMOS_menu_is_last_entry_selection() )
        item_i = i-1;

	FRM_log_obj_info( item_i );
    
	switch ( action )
	{
		case "sel":
            rc+=menu_select_item( item_i );
			break;
		case "get":
			rc+=menu_get_info( item_i, attr, outInfo );
			break;
		case "wait":
			rc+=menu_wait_info( item_i, attr, inInfo, time );
			break;
		case "chk":
			rc+=menu_get_info( item_i, attr, info );
			if ( info == inInfo )
			{
				tl_step( "EMOS_menu_check_info", PASS, sprintf("attr:%s, info:%s", attr, inInfo) );
			}
			else
			{
				tl_step( "EMOS_menu_check_info", FAIL, sprintf("attr:%s, exp:%s, act:%s", attr, inInfo, info) );
				rc+=E_MISMATCH;
			}
			break;
		default:
			rc+=E_ILLEGAL_PARAMETER;
			break;
	}

	# remove the temporary GUI-file
	rc+=GUI_close( MENFILE );
	#switch back to the original window (if possble)
	if ( win_exists( win ) == E_OK )
		rc+=set_window( win );
	return rc;
}

#**
#* This function clicks on a menu item without requiring items to be learned by
#* untilysing the WinRunner's text recognition  cpabilities.
#* <p>NOTE<p>
#*	This is an alternative to EMOS_menu_item() when this one does not seem to be
#*	stable enough (e.g. position of menu entries changes too often).
#*	This worked in very well for some applications that we were punished to test.
#*
#* @param item the item to be selected
#* @param arg_win_desc (in) (optional) physical menu window description [default: { class: object, MSW_id: 0, location: %d }]
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/


public function EMOS_menu_item_via_text ( in item, in arg_win_desc )
{
	static const SEP = ";";
	static const DEF_WIN_DESC = "{ class: object, MSW_id: 0, location: %d }"; 

    auto win_desc;
	auto arr[], count, i;
	auto rc;
	
	if ( arg_win_desc == "" )
	    win_desc = DEF_WIN_DESC;
	else
	    win_desc = arg_win_desc;
	    
	count = split( item, arr, SEP );
	if ( count < 1 )
		return E_ILLEGAL_PARAMETER;

	for ( i=1; i<count+1; i++ )
	{
		rc+=win_exists( sprintf( win_desc, i-1 ) );
#printf( "win=%s, exists=%s", sprintf( win_desc, i-1 ), rc );
		if ( index( arr[i], " " ) )
			rc+=win_move_locator_text ( sprintf( win_desc, i-1 ), arr[i], TRUE );
		else
			rc+=win_move_locator_text ( sprintf( win_desc, i-1 ), arr[i] );
#printf( "%d: item=%s rc=%s", i, arr[i], rc );
		if ( rc == E_OK )
			click("Left", 2);
	}
	return rc;
}

#**
#* This function clicks on a menu item without requiring items to be learned.
#* NOTE: It was a nice try that at some point in time worked or at least seemed to.
#* @param item the item to be selected
#* @return 
#*	E_OK: cuccess
#*	!E_OK: failure
#*/

public function EMOS_menu_select_item2 ( in item )
{
	auto rc, descr;
	rc = menu_get_desc( item, "class label parent", "class_index", "index", descr );
	if ( rc != E_OK ) return rc;
	return menu_select_item( descr );
}

#**
#*	This function implements an alternative for native menu_select_item().
#*	Try using it if the native function does not seem to work. For some
#*	mysterious reason tis function indeed manages to select more items than the
#*	native one. Note the different interface (parameter list).
#*	If you need more info, I must disapoint you. You must either dig into the 
#*	code yourself or try to get in touch with the author. I gave up.
#* @param gui1 (in)	gui-File	
#* @param win1 (in)	window
#* @param men1 (in)	menu_item		
#* @param win2 (inout)	window:	
#*<pre>		win2 = "" , dann nur Path von menu_item gibt zurück.		
#*		win2 = "*", dann sucht Name von Window in alle GUI-Filen
#*	 			(wenn Sie wissen nicht, welche Window taucht auf).		
#*		win2 # "*",dann sucht nicht (wenn Sie wissen, welche Window taucht auf).		
#*</pre>
#* @return
#*	E_OK:	Erfolg
#*	!E_OK:	 1	-	Object != menu-item or menu="sys_" or "parent"="none"
#*			 3  -	menu-item existiert nicht aufm Bildschirm
#*			 4	-	keine Beschreibung von aufgerufenem Fenster in GUI-Map 		
#*			 5	-	Menu is disabled 		
#*/

public function EMOS_menu_select_item(in gui1, in win1, in men1, inout win2 )
{
	auto rc,gui2,men2;
	
	rc = menu_select_item1(gui1, win1, men1, 3, gui2, win2, men2);

	return (rc);
}

#**
#*	The empty (does nothing) exception handler needed for menu_select_item1().
#* @param rc (in)
#* @param func (in)
#*/

public function excep1(in rc, in func)
{
#		pause("Exception: rc=" & rc & ",   func=<\"" & func & "\">");
}

#===============================================================================
# FUNCTION: menu_select_item1
#===============================================================================
# AUTHOR: Slavine
# DESCRIPTION/PURPOSE:
#	ruft auf belibiege menu_item
# PARAMETERS:
#	in  gui1 	- gui-File,		
#	in  win1 	- window,	
#	in  men1 	- menu_item,		
#	in  ttt1	- warten (sec) auf neue window für menu_item(default 3 sec)  
#	out gui2	- returns name von aufgerufener GUI-File für menu_item
#	inout win2:	- window:	
#		win2 = "" , dann nur Path von menu_item gibt zurück.		
#		win2 = "*", dann sucht Name von Window in alle GUI-Filen
#	 			wenn Sie wissen nicht, welche Window taucht auf.		
#		win2 # "*",dann sucht nicht (wenn Sie wissen, welche Window taucht auf).		
#
#	out str_menu - returns string von menu_item (z.B. "File;Open...")	
#
# RETURN VALUE:
#	E_OK:	Erfolg
#	!E_OK:	 1	-	Object != menu-item or menu="sys_" or "parent"="none"
#			 3  -	menu-item existiert nicht aufm Bildschirm
#			 4	-	keine Beschreibung von aufgerufenem Fenster in GUI-Map 		
#			 5	-	Menu is disabled 		
#
#===============================================================================
#	z.B:
#		win2 = "*";
#		gui1 = GUI_HOME & "\\Schuecal2000.gui";
#	 
#	rc = open_menu(gui1,"Schuecal2000","Glaspreise",1,gui2, win2 ,str_menu);
#	set_window(win2);
#===============================================================================

public function menu_select_item1( in gui, in win1, in men1, in ttt1, out gui2,
													 inout win2, out menu_str)
{
		auto rc,rc1,desc1,t000,num_win,num_gui;
		auto hWnd,hWnd1,hWnd2;
		auto i,i0,i1,i2,i3,i4,i5,i6,i7,i8;
		auto k0,k1,k2,k3,k4,k5,k6,k7,k8;
		auto arr1[],windows[],gui1[];
		auto rc11,rc12;

#==== warten auf neue Window oder info ==========
			if (ttt1 == 0) ttt1 = 3;
#================================================

		rc = GUI_buf_get_desc(gui,win1,men1,desc1);

		if (    index(desc1,"menu_item")  ==  0 
			 || substr(men1,1,4)  ==  "sys_"
			 || substr(desc1,index(desc1,"parent:") + 8,6) == "\"none\"")
			 return(1);
		else
		{
			rc = GUI_list_buffers(gui1, num_gui);

			i2 = 1;   i3 = 0;

			while ( i2 <= length(desc1))
			{
				k0 = substr(desc1,i2);
				i6 = index(k0,"label:");

				if (i6 == 0)   break;
				else
				{ 
					k1 = substr(k0,i6);
					i4 = index(k1,"\"") + 1;
					k2 = substr(k1, i4);

					i5 = (index(k2,"\"")  <  index(k2,"\\") ) ? index(k2,"\"") - 1 : index(k2,"\\")  - 1;

					arr1[++i3] = substr(k2,1,i5);
						
					i2 = i2 + i6 + i4 + i5 + 1;	
				}
			}

			menu_str =  arr1[i3];
			for( i7 = i3-1; i7 >=1; i7--)
				menu_str = menu_str  &  ";"  &  arr1[i7];

			EMOS_set_window(win1,10);
				
			load("win32api",1,1);
			hWnd = GetForegroundWindow();

			define_tsl_exception ("menu_get","excep1", E_ANY_ERROR,"menu_get_info");

			t000 = getvar("timeout");	setvar("timeout",ttt1);

#------------------------------------------------------
			exception_on ("menu_get");
				rc = menu_get_info(men1,"enabled",rc1);
			exception_off ("menu_get");
#------------------------------------------------------

			setvar("timeout",t000);

			if (rc   != 0)  return(3);
			if (rc1  == 0)  return(5);
			if (win2 == "") return(0);
			
			
			define_tsl_exception ("set_win", "excep1", E_ANY_ERROR,"set_window");
			define_tsl_exception ("menu_sel","excep1", E_ANY_ERROR,"menu_select_item");

#------------------------------------------------------
			exception_on ("menu_sel");
				rc = menu_select_item (men1);
			exception_off("menu_sel");
#------------------------------------------------------

			if (rc != 0)  return(3);

			if (win2 != "*")
			{
				rc = EMOS_set_window(win2,ttt1);
				return(0);
			}

			for( i7 = 1; i7 <= ttt1; i7++)
			{
				wait(1);
				if (hWnd != GetForegroundWindow())	break;
			}
			if (i7 > ttt1)	return(0);	  # kein aufgerufene Fenster or selbst sich
				
			hWnd1 = GetForegroundWindow();


			t000 = getvar("timeout");	setvar("timeout",0);

			rc  = exception_on ("set_win");

			for( i = 1; i <= num_gui; i++ )
			{
				rc = GUI_list_buf_windows(gui1[i],windows,num_win);
	
				for( i7 = 1; i7 <= num_win; i7++)
				{
					#-------------------------------
					rc1 = set_window(windows[i7],0);
					#-------------------------------
				
					if (rc1 == 0)
					{
						rc = win_get_info(windows[i7],"handle",hWnd2);

						if (hWnd1 == hWnd2)
						{
							gui2 = gui1[i];
							win2 = GUI_get_window();
							break;
						}
					}
				} 
				if (hWnd1 == hWnd2) break;
			} 
			rc  = exception_off("set_win");
			setvar("timeout",t000);

			if (i7 <= num_win) return(0);
			else			   return(4);
		}
}

###########################################################################
# TSL-LIBRARY:	EMOS_STD_menue_lib
###########################################################################