/*
	Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved.
*/


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProMenu.h>
#include <ProMessage.h>
#include <ProMdl.h> 
#include <ProModelitem.h>
#include <ProFamtable.h>
#include <ProFaminstance.h>
#include <ProParameter.h>
#include <ProSelection.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProUtil.h>
#include <ProSolid.h>
#include <ProGtol.h>
#include <ProWindows.h>
#include <ProTKRunTime.h>

#include "TestFamTab.h"
#include "TestError.h"
#include "UtilFiles.h"
#include "UtilMessage.h"
#include "UtilString.h"
#include "UtilMenu.h"
#include "UtilCollect.h"

/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
#define PROERROR_RETURN(error)    if(error != PRO_TK_NO_ERROR) return(error)
#define  OUT_FILE_EXT           ".ftb"

#define  PRO_TEST_FAM_EDIT    0
#define  PRO_TEST_FAM_SHOW    1
#define  PRO_TEST_FAM_ERASE   2


/*--------------------------------------------------------------------*\
Application data types
\*--------------------------------------------------------------------*/
typedef struct app_data
{
    ProFamtable     *p_famtab;
    ProFamtableItem *p_item;
    FILE *fp;
} ProTestAppData;

 
/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/
extern int ProTestFamAddInst (ProFamtable  *p_famtab);
extern int ProTestFamDelInst (ProFamtable  *p_famtab);
extern int ProTestFamInstRetrieve (ProFamtable  *p_famtab);
extern int ProTestFamtabActions(ProFamtable *p_famtab, int action);
extern int ProTestFamAddColumn (ProFamtable  *p_famtab);
extern int ProTestFamDelColumn (ProFamtable  *p_famtab);
extern int ProTestFamShowInst (ProFamtable  *p_famtab);
extern int ProTestFamLockInst (ProFamtable  *p_famtab);
extern int ProTestFamShowGeneric (ProFamtable  *p_famtab);
extern int ProTestFamShowFile (ProFamtable  *p_famtab);
extern int ProTestFamTypeMenu ();
ProError ProTestModelDisplay( 
    ProMdl		p_model
);

/*--------------------------------------------------------------------*\
Application static data/function
\*--------------------------------------------------------------------*/
static int ProTestFamExitActionUp(
		char *dummy,
		int type);



/*============================================================================*\
 Function:      ProTestTkFamilyMenu                           
 Purpose:       To set-up the user's family menu
\*============================================================================*/
int ProTestFamlyTabMenu(
    ProAppData		p_appdata,
    int			int_dummy
)
{
    ProMdl		p_model = *((ProMdl*)p_appdata);
    ProFamtable  	famtable;
    int          	menu_id, action;
    ProError     	status;


    status = ProFamtableInit( p_model, &famtable );
    TEST_CALL_REPORT("ProFamtableInit()", "ProTestFamlyTabMenu()",
                      status,  status != PRO_TK_NO_ERROR);

    ProMenuPush();

    ProMenuFileRegister((char *)"TkFamTab",(char *)"tkfamtab.mnu", &menu_id);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"TkFamTab",
                  (ProMenubuttonAction)ProMenuDelete, NULL,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Add Column",
                  (ProMenubuttonAction)ProTestFamAddColumn, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Del Column",
                  (ProMenubuttonAction)ProTestFamDelColumn, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Add Instance",
                  (ProMenubuttonAction)ProTestFamAddInst, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Del Instance",
                  (ProMenubuttonAction)ProTestFamDelInst, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Retr Instance",
                  (ProMenubuttonAction)ProTestFamInstRetrieve, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Edit Table",
                  (ProMenubuttonAction)ProTestFamtabActions,
                                       &famtable, PRO_TEST_FAM_EDIT);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Show Table",
                  (ProMenubuttonAction)ProTestFamtabActions,
                                       &famtable, PRO_TEST_FAM_SHOW);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Clear Table",
                  (ProMenubuttonAction)ProTestFamtabActions,
                                       &famtable, PRO_TEST_FAM_ERASE);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Show Instance",
                  (ProMenubuttonAction)ProTestFamShowInst, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Lock Instance",
                  (ProMenubuttonAction)ProTestFamLockInst, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Show generic",
                  (ProMenubuttonAction)ProTestFamShowGeneric, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Show File",
                  (ProMenubuttonAction)ProTestFamShowFile, &famtable,  0);
    ProMenubuttonActionSet((char *)"TkFamTab",(char *)"-Done TkFamTab",
                  (ProMenubuttonAction)ProMenuDelete, NULL,  0);

    ProMenuCreate(PROMENUTYPE_MAIN, (char *)"TkFamTab", &menu_id);
    ProMenuProcess((char *)"", &action);

    ProMenuPop();

  return (0);
}

/*===========================================================================*\
  Function : TestFamSelectionExtRefFilter
  Purpose  : Filter for ProSelect function (for PRO_FEAT_GEOM_COPY)
\*===========================================================================*/
ProError TestFamSelectionExtRefFilter(
    ProSelection selection,
    Pro3dPnt point,
    ProMatrix transform,
    char * option,
    int level,
    ProAppData app_data)
{
    ProFeature feat;
    ProError err;
    ProFeattype type;

    err = ProSelectionModelitemGet ( selection, &feat);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
        "TestFamSelectionExtRefFilter()", err, err != PRO_TK_NO_ERROR );

    err = ProFeatureTypeGet (&feat, &type);
    TEST_CALL_REPORT ("ProFeatureTypeGet()",
	"TestFamSelectionExtRefFilter()", err , err != PRO_TK_NO_ERROR);

    ProTKPrintf((char *)"Type: %d\n", type);
        
    return ((type == PRO_FEAT_GEOM_COPY)?(PRO_TK_NO_ERROR):(PRO_TK_CONTINUE));
}

/*===========================================================================*\
  Function : TestFamSelectionExtRefFilter
  Purpose  : Filter for ProSelect function (for PRO_FEAT_GEN_MERGE)
\*===========================================================================*/
ProError TestFamSelectionMergeFilter(
    ProSelection selection,
    Pro3dPnt point,
    ProMatrix transform,
    char * option,
    int level,
    ProAppData app_data)
{
    ProFeature feat;
    ProError err;
    ProFeattype type;

    err = ProSelectionModelitemGet ( selection, &feat);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
        "TestFamSelectionExtRefFilter()", err, err != PRO_TK_NO_ERROR );

    err = ProFeatureTypeGet (&feat, &type);
    TEST_CALL_REPORT ("ProFeatureTypeGet()",
	"TestFamSelectionExtRefFilter()", err , err != PRO_TK_NO_ERROR);

    ProTKPrintf((char *)"Type: %d\n", type);
        
    return ((type == PRO_FEAT_GEN_MERGE)?(PRO_TK_NO_ERROR):(PRO_TK_CONTINUE));
}

/*===========================================================================*\
  Function : ProTestFamTypeMenu
  Purpose  : Display the family type menu
\*===========================================================================*/
int ProTestFamTypeMenu()
{
    int action;
    static ProUtilMenuButtons col_type[] = {
	{"TkFamColType", 0, TEST_CALL_PRO_MENU_DELETE},
	{"-User Param",  PRO_FAM_USER_PARAM,    0},
	{"-Dimension",   PRO_FAM_DIMENSION,     0},
        {"-Feature",     PRO_FAM_FEATURE,       0},
        {"-Asm Comp",    PRO_FAM_ASMCOMP,       0},
        {"-Comp Model",  PRO_FAM_ASMCOMP_MODEL, 0},
        {"-Ext. ref",    PRO_FAM_EXTERNAL_REFERENCE, 0},
        {"-Merge Part",  PRO_FAM_MERGE_PART_REF,0},
	{"", 0, 0}
    };

    /*  Set-up this menu to query the user  */
    ProUtilMenuIntValueSelect(col_type, &action);
    
    return(action);
}

/*===========================================================================*\
 Function:      ProTestFamSelectItem
 Purpose:       Select a family table item
\*===========================================================================*/
ProError ProTestFamSelectItem(  
    ProFamtable		*p_famtable,	/* In:	Family table */
    ProFamtableItem	*p_item		/* Out:	Selected fam table item */
)
{
    ProMdl		p_model;
    ProModelitem	model_item;
    ProParameter        param;
    ProSelection        *sel;
    char                option[40];
    int                 n_sel = 0;
    int			type;
    ProError		status;
    ProAsmcomppath	comp_path;
    ProSelFunctions     sel_fun;

    sel_fun.pre_filter = (ProSelectionPreFilter)TestFamSelectionExtRefFilter;
    sel_fun.post_filter =  NULL;
    sel_fun.post_selact = NULL;
    sel_fun.app_data = NULL;
    
    status = ProMdlCurrentGet( &p_model );
    TEST_CALL_REPORT( "ProMdlCurrentGet()", "ProTestFamSelectItem()",
	status,  status != PRO_TK_NO_ERROR );
 
    type = ProTestFamTypeMenu();

    switch (type)
    {
      case PRO_FAM_USER_PARAM :
          status = ProMdlToModelitem( p_model, &model_item );
          TEST_CALL_REPORT( "ProMdlToModelitem()", "ProTestFamSelectItem()",
                            status,  status != PRO_TK_NO_ERROR);
          status = ProParameterSelect(&model_item, p_model, PRO_PARAMSELECT_ANY, PRO_B_FALSE, NULL, &param, NULL);
          TEST_CALL_REPORT( "ProParameterSelect()", "ProTestFamSelectItem()",
                            status, status != PRO_TK_NO_ERROR);

	  if( status != PRO_TK_NO_ERROR )
		return PRO_TK_E_NOT_FOUND;

	  status = ProParameterToFamtableItem( &param, p_item );
          TEST_CALL_REPORT( "ProParameterToFamtableItem()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);
	  break;
 
      case PRO_FAM_DIMENSION :
          ProUtilstrcpy(option, "dimension");

          status = ProSelect (option, 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
          TEST_CALL_REPORT("ProSelect()", "ProTestFamSelectItem()",
                            status, status != PRO_TK_NO_ERROR);

	  if( status != PRO_TK_NO_ERROR || n_sel < 1 )
		return PRO_TK_E_NOT_FOUND;

          status = ProSelectionModelitemGet( sel[0], &model_item );
          TEST_CALL_REPORT("ProSelectionModelitemGet()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);

          status = ProModelitemToFamtableItem( &model_item, p_item );
          TEST_CALL_REPORT("ProModelitemToFamtableItem()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);
          break;
 
      case PRO_FAM_FEATURE :
          ProUtilstrcpy(option, "feature");

          status = ProSelect (option, 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
          TEST_CALL_REPORT("ProSelect()", "ProTestFamAddColumn()",
                            status, status != PRO_TK_NO_ERROR);

	  if( status != PRO_TK_NO_ERROR || n_sel < 1 )
		return PRO_TK_E_NOT_FOUND;

          status = ProSelectionModelitemGet(sel[0], &model_item);
          TEST_CALL_REPORT("ProSelectionModelitemGet()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);
          
          ProTKPrintf((char *)"Type: %d\n", model_item.type);

          status = ProModelitemToFamtableItem( &model_item, p_item );
          TEST_CALL_REPORT("ProModelitemToFamtableItem()", 
		"ProTestFamSelectItem()",
		status, status != PRO_TK_NO_ERROR);

          break;
 
      case PRO_FAM_ASMCOMP :
      case PRO_FAM_ASMCOMP_MODEL :
	  ProUtilstrcpy(option, "prt_or_asm");

          status = ProSelect (option, 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
          TEST_CALL_REPORT("ProSelect()", "ProTestFamAddColumn()",
                            status, status != PRO_TK_NO_ERROR);

          if( status != PRO_TK_NO_ERROR || n_sel < 1 )
                return PRO_TK_E_NOT_FOUND;

	  ProSelectionAsmcomppathGet( sel[0], &comp_path );
	  if( comp_path.table_num != 1 )
	  {
		ProUtilMsgPrint( (char *)"TEST %0s", 
			(char *)"First-level assy component must be selected" );
	  }
	  
	  model_item.type = (ProType)PRO_FEAT_COMPONENT;
          model_item.owner = p_model;
          model_item.id =  comp_path.comp_id_table[0];
          
	  status = ProModelitemToFamtableItem( &model_item, p_item );
          TEST_CALL_REPORT("ProModelitemToFamtableItem()",
                "ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);

          break;

        case PRO_FAM_EXTERNAL_REFERENCE:
          ProUtilstrcpy(option, "feature");
          status = ProSelect (option, 1, NULL, &sel_fun, NULL, NULL, &sel, &n_sel);
          TEST_CALL_REPORT("ProSelect()", "ProTestFamAddColumn()",
                            status, status != PRO_TK_NO_ERROR);

	  if( status != PRO_TK_NO_ERROR || n_sel < 1 )
		return PRO_TK_E_NOT_FOUND;

          status = ProSelectionModelitemGet(sel[0], &model_item);
          TEST_CALL_REPORT("ProSelectionModelitemGet()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);

          status = ProModelitemToFamtableItem( &model_item, p_item );
          TEST_CALL_REPORT("ProModelitemToFamtableItem()", 
		"ProTestFamSelectItem()",
		status, status != PRO_TK_NO_ERROR);
        break;
        
        case PRO_FAM_MERGE_PART_REF:
          sel_fun.pre_filter =
          	 (ProSelectionPreFilter)TestFamSelectionMergeFilter;
          ProUtilstrcpy(option, "feature");
          status = ProSelect (option, 1, NULL, &sel_fun, NULL, NULL, &sel, &n_sel);
          TEST_CALL_REPORT("ProSelect()", "ProTestFamAddColumn()",
                            status, status != PRO_TK_NO_ERROR);

	  if( status != PRO_TK_NO_ERROR || n_sel < 1 )
		return PRO_TK_E_NOT_FOUND;

          status = ProSelectionModelitemGet(sel[0], &model_item);
          TEST_CALL_REPORT("ProSelectionModelitemGet()", 
		"ProTestFamSelectItem()",
                status, status != PRO_TK_NO_ERROR);

          status = ProModelitemToFamtableItem( &model_item, p_item );
          TEST_CALL_REPORT("ProModelitemToFamtableItem()", 
		"ProTestFamSelectItem()",
		status, status != PRO_TK_NO_ERROR);
        break;
        
      default :
	  status = PRO_TK_GENERAL_ERROR;
          break;
    }


    return(status);
}

/*===========================================================================*\
 Function:      ProTestFamAddColumn
 Purpose:       To add a column to a table
\*===========================================================================*/
int ProTestFamAddColumn(
    ProFamtable		*p_famtable
)
{
    ProFamtableItem	item;
    ProError		status;

    status = ProTestFamSelectItem( p_famtable, &item );

    if( status == PRO_TK_NO_ERROR )
    {
   	status = ProFamtableItemAdd( p_famtable, &item );
    	TEST_CALL_REPORT("ProFamtableItemAdd()", "ProTestFamAddColumn( )",
		status, 0);
    }

    return(status);
}

/*===========================================================================*\
 Function:      ProTestFamDelColumn
 Purpose:       To delete a column from a table
\*===========================================================================*/
int ProTestFamDelColumn(
    ProFamtable		*p_famtable
)
{
    ProFamtableItem	item;
    ProError		status;

    status = ProTestFamSelectItem( p_famtable, &item );
    
    if( status == PRO_TK_NO_ERROR )
    {
   	status = ProFamtableItemRemove( p_famtable, &item );
    	TEST_CALL_REPORT("ProFamtableItemRemove()", "ProTestFamDelColumn( )",
                      status, status != PRO_TK_NO_ERROR);
    }

    return(status);
}

/*===========================================================================*\
 Function:      ProTestFamtabInstNameCompare
 Purpose:       Compare the fam table instance name with a given string.
		Used as ProFamtableInstanceAction
 Return:	PRO_TK_E_FOUND - strings are equal, PRO_TK_NO_ERROR-otherwise
\*===========================================================================*/
ProError ProTestFamtabInstNameCompare( 
    ProFaminstance	*p_inst,
    ProError		status,
    ProAppData          app_data
)
{
    wchar_t		*p_wname = (wchar_t*)app_data;


    if( ProUtilWstrCmp( p_wname, p_inst->name ) == 0 )
	return PRO_TK_E_FOUND;
    else
	return PRO_TK_NO_ERROR;
}



/*===========================================================================*\
 Function:      ProTestFamtabInstFilter
 Purpose:       Filter for ProFamtableInstanceVisit 
\*===========================================================================*/
ProError ProTestFamtabInstFilter(
    ProFaminstance      *p_inst,
    ProAppData          app_data
)
{
    return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  Function : ProTestFamtabItemSet
  Purpose  : Set the item values of fam table instance
\*====================================================================*/
ProError ProTestFamtabItemSet(
    ProFamtableItem     *p_item,
    ProError         	status,
    ProAppData       	app_data	/* In:	Instance */
)
{
    ProFaminstance      *p_inst = (ProFaminstance*)app_data;
    ProParamvalue   	paramval;
    ProParamvalueType	paramval_type;
    wchar_t		w_buffer[ PRO_NAME_SIZE ];
    char		name[ PRO_NAME_SIZE ];
    char		str[ PRO_NAME_SIZE ];
    double		dbl_value;
    int			int_value;

    status = ProFaminstanceValueGet( p_inst, p_item, &paramval );
    TEST_CALL_REPORT( "ProFaminstanceValueGet()", "ProTestFamtabItemSet()",
	status, status != PRO_TK_NO_ERROR);
   
    if( status != PRO_TK_NO_ERROR )
	return PRO_TK_NO_ERROR;

    status = ProParamvalueTypeGet( &paramval, &paramval_type ); 
    TEST_CALL_REPORT( "ProParamvalueTypeGet()", "ProTestFamtabItemSet()",
        status, status != PRO_TK_NO_ERROR);

    ProTKSprintf( str, "Enter %s value [ENTER]: ", 
        ProWstringToString( name, p_item->string ) );
    ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", str );

    switch( paramval_type )
    {
        case PRO_PARAM_DOUBLE:
	    status = ProMessageDoubleRead( NULL, &dbl_value );
	    TEST_CALL_REPORT( "ProMessageDoubleRead()", 
		"ProTestFamtabItemSet()", status, status != PRO_TK_NO_ERROR);
	    if( status == PRO_TK_NO_ERROR )
	    {
		status = ProParamvalueSet( &paramval, (void*)&dbl_value, 
			PRO_PARAM_DOUBLE );
            	TEST_CALL_REPORT( "ProParamvalueSet()", 
                    "ProTestFamtabItemSet()", status, 
		    status != PRO_TK_NO_ERROR);
	    } 
            break;

        case PRO_PARAM_STRING:
            status = ProMessageStringRead( PRO_NAME_SIZE, w_buffer );
            TEST_CALL_REPORT( "ProMessageStringRead()", 
                "ProTestFamtabItemSet()", status, status != PRO_TK_NO_ERROR);
            if( status == PRO_TK_NO_ERROR )
            {
                status = ProParamvalueSet( &paramval, (void*)w_buffer, 
                        PRO_PARAM_STRING );
                TEST_CALL_REPORT( "ProParamvalueSet()",
                    "ProTestFamtabItemSet()", status, 
                    status != PRO_TK_NO_ERROR);
            }

            break;

        case PRO_PARAM_INTEGER:
            status = ProMessageIntegerRead( NULL, &int_value );
            TEST_CALL_REPORT( "ProMessageIntegerRead()",
                "ProTestFamtabItemSet()", status, status != PRO_TK_NO_ERROR);
            if( status == PRO_TK_NO_ERROR )
            {
                status = ProParamvalueSet( &paramval, (void*)&int_value,
                        PRO_PARAM_INTEGER );
                TEST_CALL_REPORT( "ProParamvalueSet()",
                    "ProTestFamtabItemSet()", status,
                    status != PRO_TK_NO_ERROR);
            }

            break;

        case PRO_PARAM_BOOLEAN:
        case PRO_PARAM_NOTE_ID:
        case PRO_PARAM_VOID:
            break;

        default:
            break;
    }

    status = ProFaminstanceValueSet( p_inst, p_item, &paramval );
    TEST_CALL_REPORT( "ProFaminstanceValueSet()", "ProTestFamtabItemSet()",
        status, status != PRO_TK_NO_ERROR);
 

    return PRO_TK_NO_ERROR;
}



/*===========================================================================*\
 Function:      ProTestFamtabItemFilter
 Purpose:       Filter for ProFamtableItemVisit
\*===========================================================================*/
ProError ProTestFamtabItemFilter(
    ProFamtableItem	*p_item,
    ProAppData          app_data
)
{
    return PRO_TK_NO_ERROR;
}



/*===========================================================================*\
 Function:      ProTestFamAddInst
 Purpose:       Add an instance to a family table
\*===========================================================================*/
int ProTestFamAddInst(
		ProFamtable     *p_famtable)
{
    ProError            status;
    ProFaminstance      instance;
    ProName             w_name;
    ProFaminstance *famt_instance;
    int famt_items_num, i;
    ProFamtableItem *famt_item;

    /* Enter the name of new instance */
    ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", (char *)"Enter the instance name: " );
    status = ProMessageStringRead( PRO_NAME_SIZE - 1, w_name );
    TEST_CALL_REPORT( "ProMessageStringRead()", "ProTestFamAddInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status != PRO_TK_NO_ERROR )
        return PRO_TK_NO_ERROR;

    /* See if the name already exists */
        
    status = ProUtilCollectFamtableInstance (p_famtable, &famt_instance);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)famt_instance, &famt_items_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFamAddInst()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < famt_items_num; i++)
        {
            status = ProTestFamtabInstNameCompare (famt_instance+i,
	        PRO_TK_NO_ERROR, (ProAppData)w_name);
        }
        status = ProArrayFree ((ProArray*)&famt_instance);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamAddInst()", 
            status, status != PRO_TK_NO_ERROR );
    }

    if( status == PRO_TK_E_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", 
		(char *)"The instance already exists" );
        return PRO_TK_NO_ERROR;
    }

    /* Initialize the instance handle */
    status = ProFaminstanceInit( w_name, p_famtable, &instance );
    TEST_CALL_REPORT( "ProFaminstanceInit()", "ProTestFamAddInst()",
        status, status != PRO_TK_NO_ERROR );

    /* Add the instance to the family table */
    status = ProFaminstanceAdd( &instance );
    TEST_CALL_REPORT( "ProFaminstanceAdd()", "ProTestFamAddInst()",
        status, status != PRO_TK_NO_ERROR );

    /* Set the instance values */
    
    status = ProUtilCollectFamtableItem (p_famtable, &famt_item);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)famt_item, &famt_items_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFamAddInst()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < famt_items_num; i++)
        {
            status = ProTestFamtabItemSet (famt_item+i,
	        PRO_TK_NO_ERROR, (ProAppData)&instance);
        }
        status = ProArrayFree ((ProArray*)&famt_item);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamAddInst()", 
            status, status != PRO_TK_NO_ERROR );
    }

    return status;
}



/*===========================================================================*\
 Function:      ProTestFamDelInst
 Purpose:       Delete the fam table instance  
\*===========================================================================*/
int ProTestFamDelInst(
    ProFamtable		*p_famtable
)
{
    ProError            status;
    int			n_sels;
    ProFaminstanceList	p_inst_list;


    status = ProArrayAlloc( 0, sizeof(ProFaminstance), 1, 
	(ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFamDelInst()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
        return -1;

    status = ProFaminstanceSelect( p_famtable, PRO_B_FALSE, &n_sels, 
	&p_inst_list );
    TEST_CALL_REPORT( "ProFaminstanceSelect()", "ProTestFamDelInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status != PRO_TK_NO_ERROR || n_sels < 1 )
	return -1;

    /* Bug 540831 */
    status = ProFaminstanceErase( &(p_inst_list[0]) );
    TEST_CALL_REPORT( "ProFaminstanceErase()", "ProTestFamDelInst()",
        status, status != PRO_TK_NO_ERROR );

    /* Delete the instance from the family table */
    status = ProFaminstanceRemove( &(p_inst_list[0]) );
    TEST_CALL_REPORT( "ProFaminstanceRemove()", "ProTestFamDelInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_E_NOT_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s",
                (char *)"The instance does not exist" );
    }

    status = ProArrayFree( (ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamDelInst()",
        status, status != PRO_TK_NO_ERROR );


    return(0);
}



/*===========================================================================*\
 Function:      ProTestFamShowInst
 Purpose:	Show instance model
\*===========================================================================*/
int ProTestFamShowInst(
    ProFamtable  *p_famtable)
{
    ProError            status;
    int			n_sels;
    ProFaminstanceList	p_inst_list;
    ProMdl		p_model;


    status = ProArrayAlloc( 0, sizeof(ProFaminstance), 1, 
	(ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFamShowInst()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return -1;

    status = ProFaminstanceSelect( p_famtable, PRO_B_FALSE, &n_sels, 
	&p_inst_list );
    TEST_CALL_REPORT( "ProFaminstanceSelect()", "ProTestFamShowInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status != PRO_TK_NO_ERROR || n_sels < 1 )
	return -1;

    /* Create an instance model of the specified instance handle */
    status = ProFaminstanceRetrieve( &(p_inst_list[0]), &p_model );
    TEST_CALL_REPORT( "ProFaminstanceRetrieve()", "ProTestFamShowInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_E_NOT_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s",
                (char *)"The instance does not exist" );
    }

    if( status == PRO_TK_NO_ERROR )
    {
    	/* Retrieve the handle to the instance model, if it is in session */
    	/* It's unnecessary lines. Only to test ProFaminstanceMdlGet() */
    	status = ProFaminstanceMdlGet( &(p_inst_list[0]), &p_model );
    	TEST_CALL_REPORT( "ProFaminstanceMdlGet()", "ProTestFamShowInst()",
        	status, status != PRO_TK_NO_ERROR );

    	ProTestModelDisplay( p_model );
    }

    status = ProArrayFree( (ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamShowInst()",
        status, status != PRO_TK_NO_ERROR );


    return(0);
}



/*===========================================================================*\
 Function:      ProTestFamLockInst
 Purpose:	Lock/unlock instance
\*===========================================================================*/
int ProTestFamLockInst(
    ProFamtable  *p_famtable
)
{
    ProError            status;
    int			n_sels;
    ProFaminstanceList	p_inst_list;
    int			lock_it;


    status = ProArrayAlloc( 0, sizeof(ProFaminstance), 1, 
	(ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFamLockInst()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
        return -1;

    status = ProFaminstanceSelect( p_famtable, PRO_B_FALSE, &n_sels, 
	&p_inst_list );
    TEST_CALL_REPORT( "ProFaminstanceSelect()", "ProTestFamLockInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status != PRO_TK_NO_ERROR || n_sels < 1 )
	return -1;

    /* Get the lock status */
    status = ProFaminstanceCheck( &(p_inst_list[0]), &lock_it );
    TEST_CALL_REPORT( "ProFaminstanceCheck()", "ProTestFamLockInst()",
        status, status != PRO_TK_NO_ERROR );

    lock_it = lock_it == PRO_B_TRUE ? PRO_B_FALSE : PRO_B_TRUE;

    /* Locks or unlocks the specified instance */
    status = ProFaminstanceLock( &(p_inst_list[0]), lock_it );
    TEST_CALL_REPORT( "ProFaminstanceLock()", "ProTestFamLockInst()",
        status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_E_NOT_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s",
                (char *)"The instance does not exist" );
    }

    status = ProArrayFree( (ProArray*)(&p_inst_list) );
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamLockInst()",
        status, status != PRO_TK_NO_ERROR );


    return(0);
}



/*===========================================================================*\
 Function:      ProTestFamShowGeneric
 Purpose:	Show the generic model
\*===========================================================================*/
int ProTestFamShowGeneric(
    ProFamtable  *p_famtable
)
{
    ProError            status;
    ProMdl		p_model;
    ProMdl		p_generic_model;


    status = ProMdlCurrentGet( &p_model );
    TEST_CALL_REPORT( "ProMdlCurrentGet()", "ProTestFamShowGeneric()",
        status, status != PRO_TK_NO_ERROR );

    status = ProFaminstanceGenericGet( p_model, PRO_B_FALSE, &p_generic_model );
    TEST_CALL_REPORT( "ProFaminstanceGenericGet()", "ProTestFamShowGeneric()",
        status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_E_NOT_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s",
		(char *)"The specified model is not an instance" );
        return -1;
    }

    ProTestModelDisplay( p_generic_model );


    return(0);
}



/*===========================================================================*\
  Function : ProTestFamInstRetrieve
  Purpose  : Retrieve an instance of a model from disk
\*===========================================================================*/
int ProTestFamInstRetrieve(
    ProFamtable		*p_famtable
)
{
    ProError            status;
    ProFaminstance      instance;
    ProName             w_name;
    ProMdl		p_model;
    int			is_lock;


    /* Enter the name of new instance */
    ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", (char *)"Enter the instance name: " );
    status = ProMessageStringRead( PRO_NAME_SIZE - 1, w_name );
    TEST_CALL_REPORT( "ProMessageStringRead()", "ProTestFamInstRetrieve()",
        status, status != PRO_TK_NO_ERROR );

    if( status != PRO_TK_NO_ERROR )
        return PRO_TK_NO_ERROR;

    status = ProFaminstanceInit( w_name, p_famtable, &instance );
    TEST_CALL_REPORT( "ProFaminstanceInit()", "ProTestFamInstRetrieve()",
        status, status != PRO_TK_NO_ERROR );

    status = ProFaminstanceCheck( &instance, &is_lock );
    TEST_CALL_REPORT( "ProFaminstanceCheck()", "ProTestFamInstRetrieve()",
        status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_E_NOT_FOUND )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s",
                (char *)"The instance does not exist" );
	return -1;
    }

    status = ProFaminstanceRetrieve( &instance, &p_model );
    TEST_CALL_REPORT( "ProFaminstanceRetrieve()", "ProTestFamInstRetrieve()",
        status, status != PRO_TK_NO_ERROR );

    ProTestModelDisplay( p_model );


    return 0;
}


/*===========================================================================*\
  Function : ProTestFamtabActions
  Purpose  : Test Edit, Show and Erase of the family table.
\*===========================================================================*/
int ProTestFamtabActions(
    ProFamtable  *p_famtable,
    int          action)
{
    ProError            status, status2;
    ProMdl		p_model;


    status = ProFamtableCheck(p_famtable);
    TEST_CALL_REPORT("ProFamtableCheck()", "ProTestFamtabActions()",
	status, status != PRO_TK_NO_ERROR && status != PRO_TK_EMPTY );
 
    status2 = ProMdlCurrentGet( &p_model );
    TEST_CALL_REPORT( "ProMdlCurrentGet()", "ProTestFamtabActions()",
    	status2,  status2 != PRO_TK_NO_ERROR );
    
    status2 = ProSolidFamtableCheck ((ProSolid)p_model);
    TEST_CALL_REPORT("ProSolidFamtableCheck()", "ProTestFamActions()",
    	status2, status2 != PRO_TK_NO_ERROR && status2 != PRO_TK_EMPTY );

    if ( status != PRO_TK_NO_ERROR )
    {
        ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", 
		(char *)"The family table is empty.");
	return status;
    }

    switch(action)
    {
        case PRO_TEST_FAM_EDIT:
            status = ProFamtableEdit(p_famtable);
            TEST_CALL_REPORT("ProFamtableEdit()", "ProTestFamtabActions()",
                              status, status != PRO_TK_NO_ERROR);
            break;

        case PRO_TEST_FAM_SHOW:
            status = ProFamtableShow(p_famtable);
            TEST_CALL_REPORT("ProFamtableShow()", "ProTestFamtabActions()",
                              status, status != PRO_TK_NO_ERROR);
            break;

        case PRO_TEST_FAM_ERASE:
            status = ProFamtableErase( p_famtable );
            TEST_CALL_REPORT("ProFamtableErase()", "ProTestFamtabActions()",
                              status, status != PRO_TK_NO_ERROR);

	    /* Re-init ProFamtable structure */ 
	    status = ProFamtableInit( p_model, p_famtable );
    	    TEST_CALL_REPORT("ProFamtableInit()", "ProTestFamtabActions()",
        	status,  status != PRO_TK_NO_ERROR);
            break;

        default:
            ProUtilMsgPrint( MSG_FILE_FAM, (char *)"TEST %0s", (char *)"The error in action.");
            break;
    }


  return (PRO_TK_NO_ERROR);
}

/*===========================================================================*\
  Function : ProTestFamShowFile
  Purpose  : output the family table to a file
\*===========================================================================*/
int ProTestFamShowFile(
    ProFamtable     *p_famtable)
{
  ProCharName          fname;
  ProFileName          wfname;
  ProTestAppData       data;
  ProError             status;
  ProFamtableItem      *famt_items;
  int famt_items_num, i;

  ProError ProTestVisitFamTabItems(ProFamtableItem *item, ProError status,
                                   ProAppData app_data);

    data.p_famtab = p_famtable;
    data.fp = ProUtilGenFilePtr(p_famtable->owner, (char*)OUT_FILE_EXT, fname, (char*)"w+"); 
    if(data.fp == NULL)
    {
        ProUtilMsgPrint( MSG_FILE_FAM, "TEST %0s", 
		"Cannot open file for write");
        return(PRO_TK_GENERAL_ERROR);
    }
    ProTKFprintf(data.fp, "\t\t\tFamily Table Filename : %s\n", fname);

    status = ProFamtableCheck(p_famtable);
    TEST_CALL_REPORT("ProFamtableCheck()", "ProTestFamShowFile()",
                      status, status != PRO_TK_NO_ERROR); 

    if ( status == PRO_TK_E_NOT_FOUND )
        ProTKFprintf(data.fp, "\tThe family table is empty.\n");
    else if ( status == PRO_TK_NO_ERROR )
    {                          
        status = ProUtilCollectFamtableItem (p_famtable, &famt_items);
        if (status == PRO_TK_NO_ERROR)
        {
            status = ProArraySizeGet ((ProArray)famt_items, &famt_items_num);
            TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFamShowFile()", 
                status, status != PRO_TK_NO_ERROR );
            for (i = 0; i < famt_items_num; i++)
            {
                status = ProTestVisitFamTabItems (famt_items+i,
                    PRO_TK_NO_ERROR, (ProAppData)&data);
            }
            status = ProArrayFree ((ProArray*)&famt_items);
            TEST_CALL_REPORT( "ProArrayFree()", "ProTestFamShowFile()", 
                status, status != PRO_TK_NO_ERROR );
        }
    }

    fclose(data.fp);

    ProStringToWstring(wfname, fname);
    status = ProInfoWindowDisplay(wfname, NULL, NULL);
    TEST_CALL_REPORT("ProInfoWindowDisplay()", "ProTestFamShowFile( )",
                      status, status != PRO_TK_NO_ERROR);

 
  return (PRO_TK_NO_ERROR);
}



/*====================================================================*\
  Function : ProTestFamTabItemFilter
  Purpose  : Test filter item visit function.
\*====================================================================*/
ProError ProTestFamTabItemFilter(
    ProFamtableItem *item,
    ProAppData       app_data)
{
  return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
  Function : ProTestVisitFamTabItems
  Purpose  : Visit Family Table items.
\*====================================================================*/
ProError ProTestVisitFamTabItems(
    ProFamtableItem *item,
    ProError         status,
    ProAppData       app_data)
{
    ProTestAppData 	*data = (ProTestAppData *)app_data;
    ProModelitem   	model_item;
    char           	name[PRO_NAME_SIZE];
    char			str1[PRO_NAME_SIZE];
    ProParameter		parameter;
    ProFaminstance *famt_instance;
    int famt_instance_num, i;

    ProError ProTestVisitFamTabInst(ProFaminstance *instance, ProError status,
                                  ProAppData app_data);

    data->p_item = item;

    ProWstringToString(name, item->string);
    ProTKFprintf(data->fp, "\n\tFamily Table Item (Column) : %s\n", name);

    switch( item->type )
    {
        case PRO_FAM_TYPE_UNUSED:
            ProTKSprintf(str1, "%s", "PRO_FAM_TYPE_UNUSED");
            break;
        case PRO_FAM_USER_PARAM:
            ProTKSprintf(str1, "%s", "PRO_FAM_USER_PARAM");
            break;
        case PRO_FAM_DIMENSION:
            ProTKSprintf(str1, "%s", "PRO_FAM_DIMENSION");
            break;
        case PRO_FAM_IPAR_NOTE:
            ProTKSprintf(str1, "%s", "PRO_FAM_IPAR_NOTE");
            break;
        case PRO_FAM_FEATURE:
            ProTKSprintf(str1, "%s", "PRO_FAM_FEATURE");
            break;
        case PRO_FAM_ASMCOMP:
            ProTKSprintf(str1, "%s", "PRO_FAM_ASMCOMP");
            break;
        case PRO_FAM_UDF:
            ProTKSprintf(str1, "%s", "PRO_FAM_UDF");
            break;
        case PRO_FAM_ASMCOMP_MODEL:
            ProTKSprintf(str1, "%s", "PRO_FAM_ASMCOMP_MODEL");
            break;
        case PRO_FAM_GTOL:
            ProTKSprintf(str1, "%s", "PRO_FAM_GTOL");
            break;
        case PRO_FAM_TOL_PLUS:
            ProTKSprintf(str1, "%s", "PRO_FAM_TOL_PLUS");
            break;
        case PRO_FAM_TOL_MINUS:
            ProTKSprintf(str1, "%s", "PRO_FAM_TOL_MINUS");
            break;
        case PRO_FAM_TOL_PLUSMINUS:
            ProTKSprintf(str1, "%s", "PRO_FAM_TOL_PLUSMINUS");
            break;
        case PRO_FAM_SYSTEM_PARAM:
            ProTKSprintf(str1, "%s", "PRO_FAM_SYSTEM_PARAM");
            break;
        case PRO_FAM_EXTERNAL_REFERENCE:
            ProTKSprintf(str1, "%s", "PRO_FAM_EXTERNAL_REFERENCE");
            break;
        case PRO_FAM_MERGE_PART_REF:
            ProTKSprintf(str1, "%s", "PRO_FAM_MERGE_PART_REF");
            break;
        default:
            ProTKSprintf(str1, "%s", "No Type.");
            break;
    }

    ProTKFprintf(data->fp, "\tFamilytabItem Type : %s\n", str1);

    if( item->type == PRO_FAM_USER_PARAM || 
	item->type == PRO_FAM_SYSTEM_PARAM )
    {
        status = ProFamtableItemToParameter( item, &parameter );
        TEST_CALL_REPORT( "ProFamtableItemToParameter()",
                "ProTestVisitFamTabItems( )",
                status, status != PRO_TK_NO_ERROR );

	ProWstringToString( str1, parameter.id );

        ProTKFprintf( data->fp, "\tParameter Type  : %d\n", parameter.type );
        ProTKFprintf( data->fp, "\tParameter Id    : %s\n", str1 );
    }
    else
    {
    	status = ProFamtableItemToModelitem(item, &model_item);
    	TEST_CALL_REPORT( "ProFamtableItemToModelitem()", 
		"ProTestVisitFamTabItems( )",
                status, status != PRO_TK_NO_ERROR);

        ProTKFprintf(data->fp, "\tModelitem Type  : %d\n", model_item.type);
        ProTKFprintf(data->fp, "\tModelitem Id    : %d\n", model_item.id);
    }
                      
    status = ProUtilCollectFamtableInstance (data->p_famtab, &famt_instance);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)famt_instance, &famt_instance_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestVisitFamTabItems()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < famt_instance_num; i++)
        {
            status = ProTestVisitFamTabInst (famt_instance+i,
	        PRO_TK_NO_ERROR, (ProAppData)app_data);
        }
        status = ProArrayFree ((ProArray*)&famt_instance);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestVisitFamTabItems()", 
            status, status != PRO_TK_NO_ERROR );
    }


  return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
  Function : ProTestFamTabInstFilter
  Purpose  : Test filter instance visit function.
\*====================================================================*/
ProError ProTestFamTabInstFilter(
    ProFaminstance  *instance,
    ProAppData       app_data)
{
  return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
  Function : ProTestVisitFamTabInst
  Purpose  : Visit Family Table instances.
\*====================================================================*/
ProError ProTestVisitFamTabInst(
    ProFaminstance  *instance,
    ProError         status,
    ProAppData       app_data)
{
  ProTestAppData *data = (ProTestAppData *)app_data;
  ProParamvalue   paramval;
  char            name[PRO_NAME_SIZE], str1[PRO_NAME_SIZE];

    ProWstringToString(name, instance->name);
    ProTKFprintf(data->fp, "\t\tInstance : %s;    \t", name);

/* bug - 536940  4/23/97 */
    status = ProFaminstanceValueGet(instance, data->p_item, &paramval);
    TEST_CALL_REPORT("ProFaminstanceValueGet()", "ProTestVisitFamTabInst( )",
                      status, status != PRO_TK_NO_ERROR);

    switch( paramval.type )
    {
        case PRO_PARAM_DOUBLE:
            ProTKSprintf(str1, "%lf", paramval.value.d_val);
            break;
        case PRO_PARAM_STRING:
	    ProWstringToString( str1,  paramval.value.s_val );
            break;
        case PRO_PARAM_INTEGER:
            ProTKSprintf(str1, "%d", paramval.value.i_val);
            break;
        case PRO_PARAM_BOOLEAN:
            ProTKSprintf(str1, "%d", paramval.value.l_val);
            break;
        case PRO_PARAM_NOTE_ID:
            ProTKSprintf(str1, "%s", "PRO_PARAM_NOTE_ID");
            break;
        case PRO_PARAM_VOID:
            ProTKSprintf(str1, "%s", "PRO_PARAM_VOID");
            break;
        default:
            ProTKSprintf(str1, "%s", "No Value.");
            break;
    }

    ProTKFprintf(data->fp, "\t\tValue : %s\n", str1);
    ProTKFprintf(data->fp, "\t\t\n");

  return(PRO_TK_NO_ERROR);
}



ProError ProTestModelDisplay( 
    ProMdl		p_model
)
{
    ProError		status = PRO_TK_NO_ERROR;

#ifndef PT_PRODUCTS_BUILD
    ProMdlName		w_model_name;
    ProType		model_type;
    int			win_id;


    status = ProMdlMdlnameGet( p_model, w_model_name );
    TEST_CALL_REPORT( "ProMdlMdlnameGet()", "ProTestModelDisplay()",
    	status, status != PRO_TK_NO_ERROR );

    status = ProMdlTypeGet( p_model, (ProMdlType*)&model_type );
    TEST_CALL_REPORT( "ProMdlTypeGet()", "ProTestModelDisplay()",
        status, status != PRO_TK_NO_ERROR );

    status = ProObjectwindowMdlnameCreate( w_model_name, model_type, &win_id );
    TEST_CALL_REPORT( "ProObjectwindowMdlnameCreate()", "ProTestModelDisplay()",
        status, status != PRO_TK_NO_ERROR );

    status = ProSolidDisplay( (ProSolid)p_model );
    TEST_CALL_REPORT( "ProSolidDisplay()",  "ProTestModelDisplay()",
	status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_FOUND );

#endif
    return status;
}