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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProGeomitem.h>
#include <ProGroup.h>
#include <ProSelection.h>
#include <ProSolid.h>
#include <ProModelitem.h>
#include <ProMenu.h>
#include <ProMessage.h>
#include <ProSection.h>
#include <ProUtil.h>
#include <ProPattern.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "TestFiletypes.h"
#include "UtilColor.h"
#include "UtilFiles.h"
#include "UtilFeats.h"
#include "UtilMessage.h"
#include "UtilTypes.h"
#include "UtilCollect.h"
#include "UtilVisit.h"
#include "TestFeattree.h"
#include "TestSect.h"
#include "UtilMenu.h"
#include "UtilTree.h"
#include <PTApplsUnicodeUtils.h> 
#include "TestFeat.h"
#include "TestFeattype.h"
#include "UtilTypes.h"
/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Application data types
\*--------------------------------------------------------------------*/
#define FEAT_LIST	1
#define FEAT_INFO	2
#define MODEL_INFO	3
#define	DELETE		1
#define SUPPRESS	2
#define RESUME		3

#define USER_SELECT	0
#define USER_FEAT_NUM	1
#define USER_ALL_FEAT   2
#define USER_CLEAN	3

#define USER_ACTIVATE   0
#define USER_CANCEL	1

#define USER_BEFORE	0
#define USER_AFTER	1

typedef struct testfeatdata
{
    unsigned int action; /* Bit map of FEAT_... */
    void *data;
} ProTestFeatData;
/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/
static int feature_number = 0;

/*====================================================================*\
    FUNCTION :	ProTestFailedFeatList()
    PURPOSE  :	Action for failed feat list
\*====================================================================*/
ProError ProTestFailedFeatList ()
{
    ProError status;
    ProMdl model;
    int *failed_feats, i, failed_feats_num;
    FILE *fp;
    char fname[PRO_NAME_SIZE] = "failed_feats.txt";
    ProPath w_fname;
    ProMdlType type;
    ProSelection *sel;
    ProModelitem model_item;
    int n_sel;
    
    status = ProMdlCurrentGet (&model);
    TEST_CALL_REPORT( "ProModelCurrentGet()", "ProTestFailedFeatList()",
        status, status != PRO_TK_NO_ERROR );
        
    status = ProMdlTypeGet (model, &type);
    TEST_CALL_REPORT( "ProMdlTypeGet()", "ProTestFailedFeatList()",
        status, status != PRO_TK_NO_ERROR );
        
    if (type == PRO_MDL_ASSEMBLY)
    {
        ProUtilMsgPrint("feat","TEST Select solid");
	
        status = ProSelect((char*)"feature", 1, NULL,
            NULL, NULL, NULL, &sel, &n_sel);
        TEST_CALL_REPORT("ProSelect()", "ProTestFailedFeatList()", status,
            status != PRO_TK_NO_ERROR);
        if (status != PRO_TK_NO_ERROR || n_sel < 1)
            return PRO_TK_NO_ERROR;
        
        status = ProSelectionModelitemGet (sel[0], &model_item);
        TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestFailedFeatList()", status,
            status != PRO_TK_NO_ERROR);
            
        model = model_item.owner;
    }
    
    status = ProArrayAlloc (0, sizeof (int), 1, (ProArray*)&failed_feats);
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFailedFeatList()",
        status, status != PRO_TK_NO_ERROR );
    status = ProSolidFailedFeatsList ((ProSolid)model, &failed_feats);
    TEST_CALL_REPORT( "ProSolidFailedFeatsList()", "ProTestFailedFeatList()", 
        status, status != PRO_TK_NO_ERROR &&
        status != PRO_TK_E_NOT_FOUND);
        
    if (status == PRO_TK_NO_ERROR)
    {
        fp = PTApplsUnicodeFopen (fname, "w");
        
        if (fp != NULL)
        {
            ProTKFprintf (fp, "Failed features was found\n");
            ProTKFprintf (fp, "Num\t\tID\n");
        }
            
        status = ProArraySizeGet (failed_feats, &failed_feats_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFailedFeatList()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < failed_feats_num; i++)
        {
            if (fp != NULL)
                ProTKFprintf (fp, "%d\t\t%d\n", i, failed_feats[i]);
        }
        status = ProArrayFree ((ProArray*)&failed_feats);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestFailedFeatList()", 
            status, status != PRO_TK_NO_ERROR );
            
        if (fp != NULL)
            fclose (fp);
    }
    
    ProStringToWstring (w_fname, fname);
    ProInfoWindowDisplay (w_fname, NULL, NULL);
    
    return PRO_TK_NO_ERROR;
}

/*====================================================================*\
    FUNCTION :	ProUtilResolveFeatMenu()
    PURPOSE  :	Add button to resolve feat menu
\*====================================================================*/
ProError ProUtilResolveFeatMenu ()
{
    int menu_id;
    ProError err;
    
    err = ProMenuFileRegister((char*)"RESOLVE FEAT",(char*)"reslvft.mnu", &menu_id);
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProUtilResolveFeatMenu()", 
        err, err != PRO_TK_NO_ERROR );
    err = ProMenuAuxfileRegister((char*)"RESOLVE FEAT",(char*)"reslvft.aux", &menu_id);
    TEST_CALL_REPORT( "ProMenuAuxfileRegister()", "ProUtilResolveFeatMenu()", 
        err, err != PRO_TK_NO_ERROR );
    err = ProMenubuttonActionSet((char*)"RESOLVE FEAT",(char*)"-FailedFeatsList",
        (ProMenubuttonAction)ProTestFailedFeatList, NULL, 0);
    TEST_CALL_REPORT( "ProMenubuttonActionSet()", "ProUtilResolveFeatMenu()", 
        err, err != PRO_TK_NO_ERROR );
        
    return PRO_TK_NO_ERROR;
}

/*====================================================================*\
    FUNCTION :	ProTestGeomitemAct()
    PURPOSE  :	Action function for visiting geometry items
\*====================================================================*/
ProError ProTestGeomitemAct(
    ProGeomitem *item,
    ProError instatus,
    ProAppData appdata)
{
    FILE *fp;
    char item_type[PRO_NAME_SIZE];

    fp = (FILE*)((ProTestFeatData*)appdata)->data;

/*--------------------------------------------------------------------*\
    Report the type and id
\*--------------------------------------------------------------------*/
    ProUtilObjtypeStr(item->type, item_type);
    ProTKFprintf(fp,"    %-15s %2d\n", item_type, item->id);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureGeom()
    PURPOSE  :	Function for reporting feature geometry items
\*====================================================================*/
int ProTestFeatureGeom(
    ProModelitem *feature,
    FILE *fp)
{
    ProError status;
    ProTestFeatData appdata;
    ProGeomitem	    *geomitems;
    int geomitems_num, i;

    appdata.data = fp;

    ProTKFprintf(fp, "Geometry items..\n");
    
    status = ProUtilCollectFeatureGeomitems (feature, PRO_TYPE_UNUSED, &geomitems);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)geomitems, &geomitems_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFeatureGeom()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < geomitems_num; i++)
        {
            status = ProTestGeomitemAct (&geomitems[i],
	        PRO_TK_NO_ERROR, (ProAppData)&appdata);
        }
        status = ProArrayFree ((ProArray*)&geomitems);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureGeom()", 
            status, status != PRO_TK_NO_ERROR );
    }
    return (0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureAct()
    PURPOSE  :	Generalized action function for visiting features
\*====================================================================*/
ProError ProTestFeatureAct(
    ProModelitem *feature,
    ProError instatus,
    ProAppData appdata)
{
    int action;
    FILE *fp;
    ProFeattype ftype;
    char ftype_str[PRO_NAME_SIZE];
    ProError status;
    ProBoolean visible, geomchk, read_on;
    ProFeatStatus stat;

/*--------------------------------------------------------------------*\
    Get the action type and file pointer.
\*--------------------------------------------------------------------*/
    action = ((ProTestFeatData*)appdata)->action;
    fp = (FILE*)((ProTestFeatData*)appdata)->data;

    feature_number++;

/*--------------------------------------------------------------------*\
    Get the feature type
\*--------------------------------------------------------------------*/
    status = ProFeatureTypeGet(feature, &ftype);
    TEST_CALL_REPORT("ProFeatureTypeGet()", "ProTestFeatureAct()",
				    status, status != PRO_TK_NO_ERROR);
    ProUtilFeattypeStr(ftype, ftype_str);

/*--------------------------------------------------------------------*\
    Get the feature visibility
\*--------------------------------------------------------------------*/
    status = ProFeatureVisibilityGet(feature, &visible);
    TEST_CALL_REPORT("ProFeatureVisibilityGet()", "ProTestFeatureAct()",
					status, status != PRO_TK_NO_ERROR);

    status = ProFeatureHasGeomchks(feature, &geomchk);
    TEST_CALL_REPORT("ProFeatureHasGeomchks()", "ProTestFeatureAct()",
					status, status != PRO_TK_NO_ERROR);

    status = ProFeatureIsReadonly(feature, &read_on);
    TEST_CALL_REPORT("ProFeatureIsReadonly()", "ProTestFeatureAct()",
					status, status != PRO_TK_NO_ERROR);

    if(action == FEAT_LIST)
    {
/*--------------------------------------------------------------------*\
	Report the feature id, type and visibility as a list entry
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp, "%-6d%-6d%-20s%-10s%-15s%-10s\n",
			feature_number, feature->id, ftype_str,
			visible == PRO_B_TRUE ? "" : "INTERNAL",
			geomchk == PRO_B_TRUE ? "Has geom cheks" : "",
			read_on == PRO_B_TRUE ? "Yes" : ""
			);
	return(PRO_TK_NO_ERROR);
    }
    else
    {
/*--------------------------------------------------------------------*\
	Report the feature id and type as a header 
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp,"--------------------------------------\n");
	if(visible == PRO_B_TRUE)
	    ProTKFprintf(fp,"USER FEATURE         %-d\n", feature_number);
	else
	    ProTKFprintf(fp,"INTERNAL FEATURE     %-d\n", feature_number);
	ProTKFprintf(fp,"INTERNAL ID          %-d\n", feature->id);
	ProTKFprintf(fp,"TYPE                 %s\n",  ftype_str);

/*--------------------------------------------------------------------*\
	Report everything else we know about the feature
\*--------------------------------------------------------------------*/
	ProUtilFeatureDump(feature, fp);

/*--------------------------------------------------------------------*\
	Report feature geometry
\*--------------------------------------------------------------------*/
        status = ProFeatureStatusGet(feature, &stat);
        TEST_CALL_REPORT("ProFeatureStatusGet()", "ProTestFeatureAct()",
					status, status != PRO_TK_NO_ERROR);

	if ((ftype!=PRO_FEAT_COMPONENT)&&
            ((stat==PRO_FEAT_ACTIVE)||
             (stat==PRO_FEAT_UNREGENERATED)||
             (stat==PRO_FEAT_INACTIVE))) 
                ProTestFeatureGeom(feature, fp);
    }

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
    FUNCTION : ProTestFeatCreate
    PURPOSE  : Top-level function for creating specific feature types
\*====================================================================*/
int ProTestFeatCreate(
    ProMdl		model,
    int			dummy )
{
    ProError		status;
    int			menu_id;
    int			action;
    ProFeattype		feat_type;

    ProError ProTestDtmpln();
    ProError SketchFeatureCreate();
    

    ProMenuFileRegister( (char*)"FEAT TYPE", (char*)"tkfeattype.mnu", &menu_id );
    status = ProMenubuttonActionSet((char*)"FEAT TYPE",(char*)"-Dtm Plane",
	(ProMenubuttonAction)ProUtilAssign,
	(ProAppData)&feat_type, PRO_FEAT_DATUM );
	
    status = ProMenubuttonActionSet( (char*)"FEAT TYPE", (char*)"-Protrusion",
	(ProMenubuttonAction)ProUtilAssign,
	(ProAppData)&feat_type, PRO_FEAT_PROTRUSION );
	
    status = ProMenubuttonActionSet( (char*)"FEAT TYPE", (char*)"-3D Section",
	(ProMenubuttonAction)ProUtilAssign,
	(ProAppData)&feat_type, PRO_3DSECTION );	
	
    status = ProMenubuttonActionSet( (char*)"FEAT TYPE", (char*)"FEAT TYPE",
	(ProMenubuttonAction)ProMenuHold, NULL, 0 );

    status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"FEAT TYPE", &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
        ProMenuProcess( (char*)"FEATURE CREATION", &action );
    }

    /* Call to specific feature creation function */
    switch( feat_type )
    {
	case PRO_FEAT_DATUM:
	    ProTestDtmpln();
	    break;

	case PRO_FEAT_PROTRUSION:
	    ProTestFeatureExtrudeCreate(NULL);
	    break;

	case PRO_3DSECTION:
	    SketchFeatureCreate();
	    break;
    }
	

    return 0;
}

ProError ProTestPatternCreate()
{
  int menu_id, action;
  ProError status;

  status = ProMenuFileRegister((char*)"PATTERN CREATE",(char*)"tkpatterncreate.mnu",  &menu_id);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenuFileRegister", status, status != PRO_TK_NO_ERROR );
 
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Axis Pattern",
     (ProMenubuttonAction)ProTestAxisPattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );

  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Curve Pattern",
     (ProMenubuttonAction)ProTestCurvePattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-General Pattern",
     (ProMenubuttonAction)ProTestGeneralPattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Direction Pattern",
     (ProMenubuttonAction)ProTestDirectionPattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Fill Pattern",
     (ProMenubuttonAction)ProTestFillPattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Point Pattern",
     (ProMenubuttonAction)ProTestPointPattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Table Pattern",
     (ProMenubuttonAction)ProTestTablePattern, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
             
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"-Done Return",
     (ProMenubuttonAction)ProMenuDelete, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );
  
  status = ProMenubuttonActionSet((char*)"PATTERN CREATE",(char*)"PATTERN CREATE",
                   (ProMenubuttonAction)ProMenuDelete, NULL, 0);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenubuttonActionSet", status, status != PRO_TK_NO_ERROR );

  status = ProMenuPush();
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenuPush", status, status != PRO_TK_NO_ERROR );

  status = ProMenuCreate(PROMENUTYPE_MAIN, (char*)"PATTERN CREATE", &menu_id);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenuCreate", status, status != PRO_TK_NO_ERROR );

  status = ProMenuProcess((char*)"PATTERN CREATE", &action);
  TEST_CALL_REPORT( "ProTestPatternCreate", "ProMenuProcess", status, status != PRO_TK_NO_ERROR );
 
  return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureInfo()
    PURPOSE  :	List features in current model.
\*====================================================================*/
int ProTestFeatureInfo(
    ProMdl *p_model,
    int action)
{
    ProError status;
    ProTestFeatData appdata;
    ProSelection *sel;
    int n_sel, cont=1;
    char fname[PRO_NAME_SIZE];
    wchar_t w_fname[PRO_NAME_SIZE];
    FILE *fp;
    ProFeature feature;
    ProInfoWindowLocation   win_location = { 0.0, 0.0 };
    ProInfoWindowSize	    win_size = { 25, 70 };
    ProFeature *features;
    int features_num, i;
    int *failed_feats, failed_feats_num;
    

/*--------------------------------------------------------------------*\
    Get the name of the output file
\*--------------------------------------------------------------------*/
    ProTestQcrName(p_model, (char*)FEATURES, fname);

    appdata.action = action;

    feature_number = 0;

    if(action == FEAT_INFO)
    {
/*--------------------------------------------------------------------*\
	Visit selected features
\*--------------------------------------------------------------------*/
	ProUtilMsgPrint("feat","TEST Select feature");
	while(cont)
	{
	    fp = PTApplsUnicodeFopen(fname, "w");
	    appdata.data = fp;

/*--------------------------------------------------------------------*\
	    Select a feature
\*--------------------------------------------------------------------*/
	    status = ProSelect((char*)"feature", 1, NULL,
				NULL, NULL, NULL, &sel, &n_sel);
	    TEST_CALL_REPORT("ProSelect()", "ProTestFeatureInfo()", status,
					    status != PRO_TK_NO_ERROR);
	    if(status != PRO_TK_NO_ERROR || n_sel < 1)
		break;

/*--------------------------------------------------------------------*\
	    Get the information
\*--------------------------------------------------------------------*/
	    status = ProSelectionModelitemGet(sel[0], (ProFeature *)&feature);
	    TEST_CALL_REPORT("ProSelectionModelitemGet()",
			    "ProTestFeatureInfo()",
			    status, status != PRO_TK_NO_ERROR);

	    ProTestFeatureAct(&feature, PRO_TK_NO_ERROR, &appdata);

	    fclose(fp);

	    status = ProInfoWindowDisplay( ProStringToWstring(w_fname, fname),
					    &win_location, &win_size );
	    TEST_CALL_REPORT( "ProInfoWindowDisplay()", "ProTestFeatureInfo()",
				status, status != PRO_TK_NO_ERROR );
	}
    }
    else
    {
	fp = PTApplsUnicodeFopen(fname, "w");
	appdata.data = fp;

	if(action == FEAT_LIST)
	    ProTKFprintf(fp,"Num   ID    Type\n\n");

/*--------------------------------------------------------------------*\
	Visit all the features
\*--------------------------------------------------------------------*/
	status = ProArrayAlloc (0, sizeof (int), 1, (ProArray*)&failed_feats);
	TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFeatureInfo()",
			  status, status != PRO_TK_NO_ERROR );
	status = ProSolidFailedFeatsList ((ProSolid)(*p_model), &failed_feats);
	TEST_CALL_REPORT( "ProSolidFailedFeatsList()", "ProTestFeatureInfo()", 
                status, status != PRO_TK_NO_ERROR &&
                status != PRO_TK_E_NOT_FOUND);
	if (status == PRO_TK_NO_ERROR)
	{
	    ProTKFprintf (fp, "Failed features was found\n");
	    status = ProArraySizeGet (failed_feats, &failed_feats_num);
	    TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFeatureInfo()", 
                status, status != PRO_TK_NO_ERROR );
	    for (i = 0; i < failed_feats_num; i++)
 	    {
	        ProTKFprintf (fp,"%d     %d\n", i, failed_feats[i]);
	    }
	    status = ProArrayFree ((ProArray*)&failed_feats);
	    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureInfo()", 
			      status, status != PRO_TK_NO_ERROR );
	}
	
	status = ProUtilCollectSolidFeatures ((ProSolid)*p_model, &features);
        if (status == PRO_TK_NO_ERROR)
        {
            status = ProArraySizeGet ((ProArray)features, &features_num);
            TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestFeatureInfo()", 
                status, status != PRO_TK_NO_ERROR );
            for (i = 0; i < features_num; i++)
            {
                status = ProTestFeatureAct (&features[i],
                    PRO_TK_NO_ERROR, (ProAppData)&appdata);
            }
            status = ProArrayFree ((ProArray*)&features);
            TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureInfo()", 
                status, status != PRO_TK_NO_ERROR );
        }
					
	fclose(fp);

	status = ProInfoWindowDisplay( ProStringToWstring(w_fname, fname),
					&win_location, &win_size );
	TEST_CALL_REPORT( "ProInfoWindowDisplay()", "ProTestFeatureInfo()",
			    status, status != PRO_TK_NO_ERROR );
    }


    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureSectionInfo()
    PURPOSE  :	Info about feature sections
\*====================================================================*/
int ProTestFeatureSectionInfo()
{
    FILE *fp;
    ProSection section;
    ProError err;
    ProPath w_path;

    err = ProUtilSectionFromFeatGet(&section);
    if (err != PRO_TK_NO_ERROR)
	return(-1);
    TEST_CALL_REPORT("ProUtilSectionFromFeatGet()",
		    "ProTestFeatSectionInfo()", err, err != PRO_TK_NO_ERROR );

    fp = PTApplsUnicodeFopen("section.inf", "w");
    ProStringToWstring(w_path, (char*)"section.inf");

    err = ProUtilSectionInfoGet(fp, section);
    TEST_CALL_REPORT("ProUtilSectionInfoGet()",
		    "ProTestFeatSectionInfo()", err, err != PRO_TK_NO_ERROR );

    err = ProSectionFree(&section);
    TEST_CALL_REPORT("ProSectionFree()",
		    "ProTestFeatSectionInfo()", err, err != PRO_TK_NO_ERROR );

    fclose(fp);

    err = ProInfoWindowDisplay(w_path, NULL, NULL);
    TEST_CALL_REPORT( "ProInfoWindowDisplay()", 
		    "ProTestFeatSectionInfo()", err, err != PRO_TK_NO_ERROR );

    return (0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureKill()
    PURPOSE  :	Commands "Feature Delete" and "Suppress"
\*====================================================================*/
int ProTestFeatureKill(
    ProMdl *model,
    int action)
{
    ProError status;
    int n_sel, n_children, c;
    ProFeatureDeleteOptions *delete_opts = 0;
    int *feat_ids = NULL;
    ProSelection *sel;
    ProPatternStatus pstatus;
    ProFeature children;
    int *children_ids, cont=1;
    ProSelection show;
    ProFeature feature;
    ProAsmcomppath comp_path;
    int flag_yesorno;

/*--------------------------------------------------------------------*\
    Ask the user to select features
\*--------------------------------------------------------------------*/
    ProUtilMsgPrint("feat","TEST Select feature");
    while(cont)
    {
	status = ProSelect((char*)"feature", 1, NULL,
			    NULL, NULL, NULL, &sel, &n_sel);
	TEST_CALL_REPORT("ProSelect()", "ProTestFeatureKill()", status,
					status != PRO_TK_NO_ERROR);
	if(status != PRO_TK_NO_ERROR || n_sel < 1)
	    break;

/*--------------------------------------------------------------------*\
	Check that the selected feature is not a pattern member
\*--------------------------------------------------------------------*/
	status = ProSelectionModelitemGet(sel[0], (ProFeature *)&feature);
	TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestFeatureKill()",
			status, status != PRO_TK_NO_ERROR);

	status = ProFeatureParamsDisplay( sel[0], PRO_ALL_PARAMS );
	TEST_CALL_REPORT("ProFeatureParamsDisplay()", "ProTestFeatureKill()",
	    status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

	status = ProFeaturePatternStatusGet(&feature, &pstatus);
	TEST_CALL_REPORT("ProFeaturePatternStatusGet()",
	    "ProTestFeatureKill()", status, status != PRO_TK_NO_ERROR);
	if (pstatus != PRO_PATTERN_NONE)
	{
	    ProUtilMsgPrint("feat",
		"TEST That feature belongs to a pattern");
	    continue;
	}

/*--------------------------------------------------------------------*\
	Get the list of children of the selected feature
\*--------------------------------------------------------------------*/
	status = ProFeatureChildrenGet(&feature, &children_ids, &n_children);
	TEST_CALL_REPORT("ProFeatureChildrenGet()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
	Highlight them in blue
\*--------------------------------------------------------------------*/
	status = ProSelectionAsmcomppathGet(sel[0], &comp_path);
	TEST_CALL_REPORT("ProSelectionAsmcomppathGet()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	for(c=0; c<n_children; c++)
	{
	    status = ProFeatureInit((ProSolid)feature.owner, children_ids[c], &children);
            TEST_CALL_REPORT("ProFeatureInit()", "ProTestFeatureKill()",
                                        status, status != PRO_TK_NO_ERROR);
	    status = ProSelectionAlloc(&comp_path, &children, &show);
	    TEST_CALL_REPORT("ProSelectionAlloc()", "ProTestFeatureKill()",
				status, status != PRO_TK_NO_ERROR);

	    status = ProSelectionHighlight(show, MEDIUM_BLUE);
	    TEST_CALL_REPORT("ProSelectionHighlight()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	}

/*--------------------------------------------------------------------*\
	Ask for confirmation to delete/suppress the children
\*--------------------------------------------------------------------*/
  status = ProArrayAlloc(1,sizeof(ProFeatureDeleteOptions),
      1, (ProArray*)&delete_opts);

  delete_opts[0] = PRO_FEAT_DELETE_CLIP;

  status = ProArrayAlloc(1,sizeof(int),
      1, (ProArray*)&feat_ids);

  feat_ids[0] = feature.id;

	if(n_children > 0)
	{
	    ProUtilMsgPrint("feat",
			"TEST Do you want to %0s the features in blue too? [yes] : ",
			action == DELETE ? "delete" : "suppress");
	    flag_yesorno = ProUtilYesnoGet((char*)"yes");
	    
	    if(flag_yesorno != 1)
	    {
	    	delete_opts[0] = PRO_FEAT_DELETE_NO_OPTS;
	    }
	    	
	}

	if(action == DELETE)
	{

	    status = ProFeatureWithoptionsDelete((ProSolid)feature.owner, feat_ids,
					delete_opts, PRO_REGEN_NO_FLAGS);
	    TEST_CALL_REPORT("ProFeatureWithoptionsDelete()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	    status = ProWindowRepaint(-1);
	    TEST_CALL_REPORT("ProWindowRepaint()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	}
	else
	{
	    status = ProFeatureWithoptionsSuppress((ProSolid)feature.owner, feat_ids,
					delete_opts, PRO_REGEN_NO_FLAGS);
	    TEST_CALL_REPORT("ProFeatureWithoptionsSuppress()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	    status = ProWindowRepaint(-1);
	    TEST_CALL_REPORT("ProWindowRepaint()", "ProTestFeatureKill()",
					status, status != PRO_TK_NO_ERROR);
	}
     status = ProArrayFree((ProArray*)&delete_opts);
     status = ProArrayFree((ProArray*)&feat_ids);
    }

    status = ProTreetoolRefresh(*model);
    TEST_CALL_REPORT("ProTreetoolRefresh()",
		    "ProTestFeatureKill()", status, status != PRO_TK_NO_ERROR);
    return(0);
}



/*====================================================================*\
    FUNCTION :	proTestFeatureResume()
    PURPOSE  :	Command "Resume"
\*====================================================================*/
int ProTestFeatureResume( ProSolid* p_solid)
{
    ProError	    status;
    int*	    p_feat_id_array;
    ProFeatStatus*  p_status_array;
    int		    n_features;
    int		    n_suppressed;
    int		    i;
    ProFeature	    feature;
    ProBoolean	    is_incomplete;
    ProFeatureResumeOptions *resume_options = 0;


    /* Allocate ID and status arrays */
    status = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );
    status = ProArrayAlloc( 0, sizeof(ProFeatStatus), 1, (ProArray *)&p_status_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return -1;

    /* Get a list of features of the specified solid and their statuses */
    status = ProSolidFeatstatusGet( *p_solid, &p_feat_id_array, &p_status_array, 
	&n_features );
    TEST_CALL_REPORT( "ProSolidFeatstatusGet()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return -1;

    for( i=n_features-1, n_suppressed=0; i>=0; i-- )
    {
	/* Get a handle to the feature */
	status = ProFeatureInit( *p_solid, p_feat_id_array[i], &feature );
	TEST_CALL_REPORT( "ProFeatureInit()", "ProTestFeatureResume()",
			    status, status != PRO_TK_NO_ERROR );

	/* Is feature complete? */
	is_incomplete = PRO_B_FALSE;
	status = ProFeatureIsIncomplete( &feature, &is_incomplete );
	TEST_CALL_REPORT( "ProFeatureIsIncomplete()", "ProTestFeatureResume()",
			    status, status != PRO_TK_NO_ERROR );

	/* Remove incomplete feature from the array */
	if( is_incomplete == PRO_B_TRUE || 
	    p_status_array[i] != PRO_FEAT_SUPPRESSED)
	{
	    status = ProArrayObjectRemove( (ProArray *)&p_feat_id_array, i, 1 );
	    TEST_CALL_REPORT( "ProArrayObjectRemove()", 
				"ProTestFeatureResume()",
				status, status != PRO_TK_NO_ERROR );
	}
	else
	    n_suppressed++;
    }

    /* Resume suppressed features */
    status = ProArrayAlloc(1,sizeof(ProFeatureResumeOptions),
        1, (ProArray*)&resume_options);

    resume_options[0] = PRO_FEAT_RESUME_INCLUDE_PARENTS;

    status = ProFeatureWithoptionsResume( *p_solid, p_feat_id_array, 
				resume_options, PRO_REGEN_NO_FLAGS);
    TEST_CALL_REPORT( "ProFeatureWithoptionsResume()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );

    /* Refresh win */
    status = ProWindowRepaint(-1);
    TEST_CALL_REPORT("ProWindowRepaint()", "ProTestFeatureResume()",
				status, status != PRO_TK_NO_ERROR);

    status = ProTreetoolRefresh((ProMdl)*p_solid);
    TEST_CALL_REPORT("ProTreetoolRefresh()",
		"ProTestFeatureResume()", status, status != PRO_TK_NO_ERROR);

    /* Free pre-allocated */
    status = ProArrayFree((ProArray*)&resume_options);
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );

    status = ProArrayFree( (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );
    status = ProArrayFree( (ProArray *)&p_status_array );
    TEST_CALL_REPORT( "ProArrayFree()", "ProTestFeatureResume()",
			status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return -1;


    return 0;
}

/*====================================================================*\
    FUNCTION :	ProUtilFeatByNumberInit()
    PURPOSE  :	Set Read Only status for feature
\*====================================================================*/
ProError ProUtilFeatByNumberInit(
    ProSolid solid,
    int feature_num,
    ProFeature *p_feature)
{
    ProError err, status = PRO_TK_GENERAL_ERROR;
    int *p_feat_id_array, n_features;
    ProFeatStatus *p_status_array;
    int feature_count; 
    int actual_feat_number = 0; 
    ProBoolean feature_found = PRO_B_FALSE;


    /* Allocate ID and err arrays */
    err = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProUtilFeatByNumberInit()",
					    err, err != PRO_TK_NO_ERROR);
    if( err != PRO_TK_NO_ERROR )
	return (PRO_TK_GENERAL_ERROR);

    err = ProArrayAlloc( 0, sizeof(ProFeatStatus), 1, 
	(ProArray *)&p_status_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProUtilFeatByNumberInit()",
					    err, err != PRO_TK_NO_ERROR);
    if( err != PRO_TK_NO_ERROR )
	return (PRO_TK_GENERAL_ERROR);

    /* Get a list of features of the specified solid and their erres */
    err = ProSolidFeatstatusGet(solid, &p_feat_id_array, &p_status_array,
	&n_features );
    TEST_CALL_REPORT( "ProSolidFeatstatusGet()", "ProUtilFeatByNumberInit()",
			err, err != PRO_TK_NO_ERROR );

    /* feature_num--; */ 

    if (err == PRO_TK_NO_ERROR && ( n_features > (feature_num-1) ) )
    {
	for ( feature_count = 0;  feature_count < n_features;  feature_count++ ) 
    	{ 
    	if ( p_status_array[feature_count] == PRO_FEAT_ACTIVE ) actual_feat_number++; 
    	if ( actual_feat_number == feature_num ) 
         { 
         feature_found = PRO_B_TRUE; 
         break; 
         } 
    	} 

    if ( feature_found ) 
        { 
        status = ProFeatureInit(solid, p_feat_id_array[feature_count],p_feature); 

        err = ProArrayFree((ProArray*)&p_feat_id_array );
        TEST_CALL_REPORT( "ProArrayFree()", "ProUtilFeatByNumberInit()",
					    err, err != PRO_TK_NO_ERROR);

        err = ProArrayFree((ProArray*)&p_status_array );
        TEST_CALL_REPORT( "ProArrayFree()", "ProUtilFeatByNumberInit()",
					    err, err != PRO_TK_NO_ERROR);
	return ( status ); 
	/* Returns for a successful call from here */ 
        } 
        else 
        { 
        return PRO_TK_E_NOT_FOUND; 

		/* Includes the cases for 
  		1.The input value of the feature_number being greater than the number of
     		ACTIVE features available in the model , but less than the max id 
		*/ 
        } 
    } 
    else 
    { 
    return PRO_TK_BAD_CONTEXT; 
		/* Includes the cases for 
  		1.Non-successful call to ProSolidFeatstatusGet and 
  		2.The input value of the feature number being greater than the number of id's collected 
		*/ 
    }


}


/*====================================================================*\
    FUNCTION :	ProUtilSolidLastFeatGet()
    PURPOSE  :	Set Read Only status for feature
\*====================================================================*/
ProError ProUtilSolidLastFeatGet(
    ProSolid solid,
    int *last_feature)
{
    ProError err, status;
    int *p_feat_id_array, n_features;
    ProFeatStatus *p_status_array;

    /* Allocate ID and err arrays */
    err = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProUtilSolidLastFeatGet()",
					    err, err != PRO_TK_NO_ERROR);
    if( err != PRO_TK_NO_ERROR )
	return (PRO_TK_GENERAL_ERROR);

    err = ProArrayAlloc( 0, sizeof(ProFeatStatus), 1, 
	(ProArray *)&p_status_array );
    TEST_CALL_REPORT( "ProArrayAlloc()", "ProUtilSolidLastFeatGet()",
					    err, err != PRO_TK_NO_ERROR);
    if( err != PRO_TK_NO_ERROR )
	return (PRO_TK_GENERAL_ERROR);

    /* Get a list of features of the specified solid and their erres */
    err = ProSolidFeatstatusGet(solid, &p_feat_id_array, &p_status_array,
	&n_features );
    TEST_CALL_REPORT( "ProSolidFeatstatusGet()", "ProUtilSolidLastFeatGet()",
			err, err != PRO_TK_NO_ERROR );

    status = err;

    err = ProArrayFree((ProArray*)&p_feat_id_array );
    TEST_CALL_REPORT( "ProArrayFree()", "ProUtilSolidLastFeatGet()",
					    err, err != PRO_TK_NO_ERROR);
    err = ProArrayFree((ProArray*)&p_status_array );
    TEST_CALL_REPORT( "ProArrayFree()", "ProUtilSolidLastFeatGet()",
					    err, err != PRO_TK_NO_ERROR);

    if (status == PRO_TK_NO_ERROR)
	last_feature[0] = n_features;
    else
	last_feature[0] = 0;

    return(status);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureReadOnlySet()
    PURPOSE  :	Set Read Only status for feature
\*====================================================================*/
int ProTestFeatureReadOnlySet(
    ProSolid *p_solid,
    int option)
{
    ProError err;
    ProSelection *sel;
    int n_sel, max_feat, irange[2], i, ok=0;
    ProFeature feature;

    switch(option)
    {
	case USER_SELECT:
	    ProUtilMsgPrint("feat","TEST Select feature");
	    err = ProSelect((char*)"feature", 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
	    if (err != PRO_TK_NO_ERROR || n_sel != 1)
		break;

	    err = ProSelectionModelitemGet(sel[0], (ProFeature *)&feature);
	    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		"ProTestFeatureReadOnlySet()", err, err != PRO_TK_NO_ERROR);

	    ok = 1;
	    break;
	case USER_FEAT_NUM:
	    err = ProUtilSolidLastFeatGet(p_solid[0], &max_feat);
	    if (err != PRO_TK_NO_ERROR || max_feat <=0)
		break;

	    ProUtilMsgPrint("feat",
		"TEST Enter feature regeneration number (1 - %0d) [QUIT]:",
		&max_feat);
	    irange[0] = 1;
	    irange[1] = max_feat;
	    err = ProMessageIntegerRead(irange, &i);
	    if (err != PRO_TK_NO_ERROR)
		break;

	    err = ProUtilFeatByNumberInit(p_solid[0], i, &feature);
	    if (err != PRO_TK_NO_ERROR)
		break;

	    ok = 1;
	    break;
	case USER_ALL_FEAT:
	    err = ProUtilSolidLastFeatGet(p_solid[0], &max_feat);
	    if (err != PRO_TK_NO_ERROR || max_feat <=0)
		break;

	    err = ProUtilFeatByNumberInit(p_solid[0], max_feat, &feature);
	    if (err != PRO_TK_NO_ERROR)
		break;

	    ok = 1;
	    break;
	case USER_CLEAN:
	    err = ProFeatureReadonlyUnset(p_solid[0]);
	    TEST_CALL_REPORT("ProFeatureReadonlyUnset()",
		"ProTestFeatureReadOnlySet()", err, err != PRO_TK_NO_ERROR);

	    ProUtilMsgPrint("feat", "TEST Read-only setting has been cleaned.");
	    ok = 2;
	    break;
	default:
	    ProTKPrintf("Error: ProTestFeatureReadOnlySet unknown action\n");
	    break;
    }

    if (ok == 1)
    {
	err = ProFeatureReadonlySet(&feature);
	TEST_CALL_REPORT("ProFeatureReadonlySet()",
		"ProTestFeatureReadOnlySet()", err, err != PRO_TK_NO_ERROR);

	ProUtilMsgPrint("feat", 
	    "TEST Features up to and feat ID %0d are now read only.", 
	    &feature.id);
    }

    if (ok > 0)
    {
	err = ProMenuDelete();
	TEST_CALL_REPORT("ProMenuDelete()",
		    "ProTestFeatureReadOnlySet()", err, err != PRO_TK_NO_ERROR);
    }
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureReadOnly()
    PURPOSE  :	Show tkR-only feat menu 
\*====================================================================*/
int ProTestFeatureReadOnly(ProSolid *p_solid)
{
    ProError status;
    int menu_id, action;

    status = ProMenuFileRegister((char*)"tkR-only feat", (char*)"tkronlyfeat.mnu", &menu_id);
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestFeatureReadOnly()", 
				    status, status != PRO_TK_NO_ERROR );

    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"Select", 
	(ProMenubuttonAction)ProTestFeatureReadOnlySet, 
	p_solid, USER_SELECT);
    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"Feat Num", 
	(ProMenubuttonAction)ProTestFeatureReadOnlySet, 
	p_solid, USER_FEAT_NUM);
    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"All Feat", 
	(ProMenubuttonAction)ProTestFeatureReadOnlySet, 
	p_solid, USER_ALL_FEAT);
    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"Clean", 
	(ProMenubuttonAction)ProTestFeatureReadOnlySet, 
	p_solid, USER_CLEAN);
    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"Done/Return", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0); 
    ProMenubuttonActionSet((char*)"tkR-only feat", (char*)"tkR-only feat", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0); 

    ProMenuPush();
    ProMenuCreate(PROMENUTYPE_MAIN, (char*)"tkR-only feat", &menu_id);
    status = ProMenuCommandPush((char*)"Select");
    TEST_CALL_REPORT( "ProMenuCommandPush()", "ProTestFeatureReadOnly()", 
				    status, status != PRO_TK_NO_ERROR );
    ProMenuProcess((char*)"tkR-only feat", &action);
    ProMenuPop();

    return (0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureInsertModeSet
    PURPOSE  :	Set/Cancel Insert mode
\*====================================================================*/
int ProTestFeatureInsertModeSet(
    ProSolid *p_solid,
    int option)
{
    ProError err;
    ProSelection *sel;
    int n_sel, max_feat, feat_num, ok = 0;
    ProBoolean resume;
    ProFeature feature;

    switch (option)
    {
	case USER_ACTIVATE:
	    do
	    {
	    ProUtilMsgPrint("feat", "Test Select a feature to insert after.");
	    err = ProSelect((char*)"feature", 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
	    if (err != PRO_TK_NO_ERROR || n_sel != 1)
		break;

	    err = ProSelectionModelitemGet(sel[0], (ProFeature *)&feature);
	    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		"ProTestFeatureInsertModeSet()", err, err != PRO_TK_NO_ERROR);
	    
	    err = ProUtilSolidLastFeatGet(p_solid[0], &max_feat);
	    if (err != PRO_TK_NO_ERROR || max_feat <=0)
		break;

	    err = ProFeatureNumberGet(&feature, &feat_num);
	    TEST_CALL_REPORT("ProFeatureNumberGet()",
		"ProTestFeatureInsertModeSet()", err, err != PRO_TK_NO_ERROR);

	    if (err != PRO_TK_NO_ERROR)
		break;

	    if (feat_num == max_feat)
	    {
		ProUtilMsgPrint("feat", "Test Can not select last feature.");
		continue;
	    }

	    err = ProFeatureInsertmodeWithoptionsActivate(&feature,PRO_REGEN_NO_FLAGS);
	    TEST_CALL_REPORT("ProFeatureInsertmodeWithoptionsActivate()",
		"ProTestFeatureInsertModeSet()", err, err != PRO_TK_NO_ERROR);

	    ok = 1;
	    } while (ok ==0);
	    break;
	case USER_CANCEL:
	    ProUtilMsgPrint("feat", "TEST Resume features that were "
		"suppressed when activating insert mode? [Y]:");
	    resume = (ProBoolean)ProUtilYesnoGet((char*)"yes");

	    err = ProInsertmodeWithoptionsCancel(p_solid[0], resume,PRO_REGEN_NO_FLAGS);
	    TEST_CALL_REPORT("ProInsertmodeWithoptionsCancel()",
		"ProTestFeatureInsertModeSet()", err, err != PRO_TK_NO_ERROR);

	    ProUtilMsgPrint("feat", "TEST Insert mode has been canceled.");
	    ok = 1;
	    break;
    }

    if (ok == 1)
    {
	err = ProTreetoolRefresh((ProMdl)*p_solid);
	TEST_CALL_REPORT("ProTreetoolRefresh()",
	    "ProTestFeatureInsertModeSet()", err, err != PRO_TK_NO_ERROR);

	ProMenuDelete();
    }
    return (0);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureInsertMode
    PURPOSE  :	Show TkIns Mode Menu
\*====================================================================*/
int ProTestFeatureInsertMode(
    ProSolid *p_solid)
{
    ProError status;
    int menu_id, action;
    ProBoolean bool_flag;

    status = ProMenuFileRegister((char*)"tkinsert mode", (char*)"tkinsertmode.mnu", &menu_id);
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestFeatureInsertMode()", 
				    status, status != PRO_TK_NO_ERROR );

    ProMenubuttonActionSet((char*)"tkinsert mode", (char*)"Activate", 
	(ProMenubuttonAction)ProTestFeatureInsertModeSet, 
	p_solid, USER_ACTIVATE);
    ProMenubuttonActionSet((char*)"tkinsert mode", (char*)"Cancel", 
	(ProMenubuttonAction)ProTestFeatureInsertModeSet, 
	p_solid, USER_CANCEL);
    ProMenubuttonActionSet((char*)"tkinsert mode", (char*)"Return", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0); 
    ProMenubuttonActionSet((char*)"tkinsert mode", (char*)"tkinsert mode", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0); 

    status = ProInsertModeIsActive(p_solid[0], &bool_flag);
    TEST_CALL_REPORT( "ProInsertModeIsActive()", "ProTestFeatureInsertMode()", 
				    status, status != PRO_TK_NO_ERROR );

    ProMenuPush();
    ProMenuCreate(PROMENUTYPE_MAIN, (char*)"tkinsert mode", &menu_id);
    if (bool_flag == PRO_B_FALSE)
    {
	status = ProMenubuttonActivate((char*)"tkinsert mode", (char*)"Activate");
	TEST_CALL_REPORT("ProMenubuttonActivate()",
	    "ProTestFeatureInsertMode()", status, status != PRO_TK_NO_ERROR );
	status = ProMenubuttonDeactivate((char*)"tkinsert mode", (char*)"Cancel");
	TEST_CALL_REPORT("ProMenubuttonDeactivate()",
	    "ProTestFeatureInsertMode()", status, status != PRO_TK_NO_ERROR );
    }
    else
    {
	status = ProMenubuttonActivate((char*)"tkinsert mode", (char*)"Cancel");
	TEST_CALL_REPORT("ProMenubuttonActivate()",
	    "ProTestFeatureInsertMode()", status, status != PRO_TK_NO_ERROR );
	status = ProMenubuttonDeactivate((char*)"tkinsert mode", (char*)"Activate");
	TEST_CALL_REPORT("ProMenubuttonDeactivate()",
	    "ProTestFeatureInsertMode()", status, status != PRO_TK_NO_ERROR );
    }
    ProMenuProcess((char*)"tkinsert mode", &action);
    ProMenuPop();

    return (0);
}

/*====================================================================*\
    FUNCTION :	ProUtilSortedIntArrayObjectAdd
    PURPOSE  :	Add int value to sorted array of int
\*====================================================================*/
ProError ProUtilSortedIntArrayObjectAdd(
    int **p_array,
    int new_value)
{
    ProError err;
    int i, size;

    err = ProArraySizeGet((ProArray)p_array[0], &size);
    TEST_CALL_REPORT("ProArraySizeGet()",
	    "ProUtilSortedIntArrayObjectAdd()", err, err != PRO_TK_NO_ERROR );

    for (i=0; i<size && new_value>p_array[0][i]; i++);
    if (i>=size || new_value<p_array[0][i])
    {
	err = ProArrayObjectAdd((ProArray*)p_array, i, 1, &new_value);
	TEST_CALL_REPORT("ProArrayObjectAdd()",
	    "ProUtilSortedIntArrayObjectAdd()", err, err != PRO_TK_NO_ERROR );
    }

    return (err);
}

/*====================================================================*\
    FUNCTION :	ProUtilReorderPreFilter
    PURPOSE  :	filter function to reorder feats
\*====================================================================*/
ProError ProUtilReorderPreFilter(
    ProSelection sel,
    Pro3dPnt	pnt,
    ProMatrix trans,
    char *option,
    int level,
    ProAppData	appdata)
{
    ProSolid *p_solid = (ProSolid*)appdata;
    ProMdlName w_name;
    ProError err;
    ProModelitem modelitem;

    TEST_CALL_REPORT("ProSelectionPreFilter()", 
					   "ProUtilReorderPreFilter()", PRO_TK_NO_ERROR, 0);

    err = ProSelectionModelitemGet(sel, &modelitem);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		"ProUtilReorderPreFilter()", err, err != PRO_TK_NO_ERROR );
    if (modelitem.owner != (ProMdl)p_solid[0])
    {
	err = ProMdlMdlnameGet(modelitem.owner, w_name);
	TEST_CALL_REPORT("ProMdlMdlnameGet()",
		"ProUtilReorderPreFilter()", err, err != PRO_TK_NO_ERROR );
	ProUtilMsgPrint("feat", "Test Select from %0w please.", w_name);
	return (PRO_TK_CONTINUE);
    }

    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestFeatureReorder
    PURPOSE  :	Reorder features
\*====================================================================*/
int ProTestFeatureReorder(
    ProSolid *p_solid)
{    
    ProError err;
    int *feat_arr = NULL, n_sel, stop = 0, i, ok=0;
    int feat_num, *p_feat_id_array = NULL;
    ProSelection *sel;
    ProModelitem modelitem;
    ProSelFunctions filter;
    ProFeatStatus *p_status_array = NULL;

    ProUtilMsgPrint("feat", "Test Select features to reorder. Multiple features"
	" must be in consecutive order.");

    memset(&filter, '\0', sizeof(filter));
    filter.pre_filter = (ProSelectionPreFilter)ProUtilReorderPreFilter;
    filter.app_data = (ProAppData)p_solid;

    do
    {

    err = ProSelect((char*)"feature", -1, NULL, &filter, NULL, NULL, &sel, &n_sel);
    if (err != PRO_TK_NO_ERROR)
	break;

    /* Sort features array by number */
    ProArrayAlloc(0, sizeof(int), 1, (ProArray*)&feat_arr);
    for (i=0; i<n_sel; i++)
    {
	err = ProSelectionModelitemGet(sel[i], &modelitem);
	TEST_CALL_REPORT("ProSelectionModelitemGet()",
	    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);

	err = ProFeatureNumberGet((ProFeature*)&modelitem, &feat_num);
	if (err != PRO_TK_NO_ERROR)
	    continue;    

	ProUtilSortedIntArrayObjectAdd(&feat_arr, feat_num);
    }
    
    ProUtilMsgPrint("feat", "Test Select a feature to insert after.");
    err = ProSelect((char*)"feature", 1, NULL, &filter, NULL, NULL, &sel, &n_sel);
    if (err != PRO_TK_NO_ERROR || n_sel != 1)
	break;

    err = ProSelectionModelitemGet(sel[0], &modelitem);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);

    err = ProFeatureNumberGet((ProFeature*)&modelitem, &feat_num);
    if (err != PRO_TK_NO_ERROR)
	break;    

    feat_num++;
    ProArraySizeGet((ProArray)feat_arr, &n_sel);

    /* Show possibility to reorder features in two modes */
    err = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT("ProArrayAlloc()",
		"ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
	break;

    for (i=0; i<n_sel; i++)
    {
	err = ProUtilFeatByNumberInit(p_solid[0], feat_arr[i],
	    (ProFeature*)&modelitem);
    	TEST_CALL_REPORT("ProUtilFeatByNumberInit()",
		"ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);

	ProArrayObjectAdd((ProArray*)&p_feat_id_array, PRO_VALUE_UNUSED,
	    1, &modelitem.id);
    }

    err = ProFeatureReorder(p_solid[0], p_feat_id_array, n_sel, feat_num);
    TEST_CALL_REPORT("ProFeatureReorder()",
		"ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    
    if (err != PRO_TK_NO_ERROR)
	break;

    ok =1;

    } while (stop);
    
    if (feat_arr != NULL)
    {
	err = ProArrayFree((ProArray*)&feat_arr);
	TEST_CALL_REPORT( "ProArrayFree()",
		    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    }
    if (p_feat_id_array != NULL)
    {
	err = ProArrayFree((ProArray*)&p_feat_id_array);
	TEST_CALL_REPORT( "ProArrayFree()",
		    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    }
    if (p_status_array != NULL)
    {
	err = ProArrayFree((ProArray*)&p_status_array);
	TEST_CALL_REPORT( "ProArrayFree()",
		    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    }
    if (ok == 1)
    {
	err = ProTreetoolRefresh((ProMdl)*p_solid);
	TEST_CALL_REPORT("ProTreetoolRefresh()",
		    "ProTestFeatureReorder()", err, err != PRO_TK_NO_ERROR);
    }
    return (0);
}

/*====================================================================*\
FUNCTION : ProTestFeatTreeInfoGet
PURPOSE  : The main function for getting the feature tree definition
\*====================================================================*/
int ProTestFeatTreeInfoGet()
{
    ProError err;
    ProFeature feature;
    ProElement elemtree;
    ProSelection *p_sel;
    int n_sel;

    ProUtilMsgPrint("feat", "TEST Select feature");    
    
    err = ProSelect((char*)"feature", 1, NULL, NULL, NULL, NULL, &p_sel, &n_sel);
    if (err != PRO_TK_NO_ERROR)
	return (0);

    err = ProSelectionModelitemGet(p_sel[0], (ProModelitem *)&feature);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		    "ProTestFeatTreeInfoGet", err , err != PRO_TK_NO_ERROR);

    err = ProFeatureElemtreeExtract(&feature, NULL,  PRO_FEAT_EXTRACT_NO_OPTS, &elemtree );
    TEST_CALL_REPORT("ProFeatureElemtreeExtract()","ProTestFeatTreeInfoGet",
                            err , err != PRO_TK_NO_ERROR);

    if(err == PRO_TK_INVALID_TYPE)
      ProUtilMsgPrint("gen","TEST %0s",
			    "Elem Tree isn't supported for this feature");
    else if(err != PRO_TK_NO_ERROR)
	    ProUtilMsgPrint("gen","TEST %0s","Error getting the elem tree");
      else
         ProUtilShowTreeInInfo(elemtree);
 
    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProTestLocalGroupCreate
PURPOSE  : Function to test local group
\*====================================================================*/
int ProTestLocalGroupCreate(    
    ProSolid *p_solid)
{
    ProError err;
    ProName  w_name;
    int *feat_arr = NULL, n_sel, stop = 0, i, *p_feat_id_array, feat_num;
    ProSelection *sel;
    ProModelitem modelitem;
    ProGroup group;

    ProUtilMsgPrint("feat", "Test Enter group name [QUIT]:");
    if (ProMessageStringRead(PRO_NAME_SIZE, w_name) != PRO_TK_NO_ERROR)
	return (-1);

    ProUtilMsgPrint("feat", "Test Select features to form a group.");

    do
    {

    err = ProSelect((char*)"feature", -1, NULL, NULL, NULL, NULL, &sel, &n_sel);
    if (err != PRO_TK_NO_ERROR)
	break;

    /* Sort features array by number */
    ProArrayAlloc(0, sizeof(int), 1, (ProArray*)&feat_arr);
    for (i=0; i<n_sel; i++)
    {
	err = ProSelectionModelitemGet(sel[i], &modelitem);
	TEST_CALL_REPORT("ProSelectionModelitemGet()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);

	err = ProFeatureNumberGet((ProFeature*)&modelitem, &feat_num);
	if (err != PRO_TK_NO_ERROR)
	    continue;    

	ProUtilSortedIntArrayObjectAdd(&feat_arr, feat_num);
    }

    err = ProArraySizeGet((ProArray)feat_arr, &n_sel);
    TEST_CALL_REPORT("ProArraySizeGet()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);
    
    err = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&p_feat_id_array );
    TEST_CALL_REPORT("ProArrayAlloc()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
	break;

    for (i=0; i<n_sel; i++)
    {
	err = ProUtilFeatByNumberInit(p_solid[0], feat_arr[i],
	    (ProFeature*)&modelitem);

	ProArrayObjectAdd((ProArray*)&p_feat_id_array, PRO_VALUE_UNUSED,
	    1, &modelitem.id);
    }

    err = ProLocalGroupCreate((ProSolid)modelitem.owner, p_feat_id_array, n_sel, w_name,
	&group);
    TEST_CALL_REPORT("ProLocalGroupCreate()",
		"ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);
    
    err = ProArrayFree((ProArray*)&feat_arr);
    TEST_CALL_REPORT("ProArrayFree()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);

    err = ProArrayFree((ProArray*)&p_feat_id_array);
    TEST_CALL_REPORT("ProArrayFree()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);

    } while (stop);
    
    err = ProTreetoolRefresh(modelitem.owner);
    TEST_CALL_REPORT("ProTreetoolRefresh()",
		    "ProTestLocalGroupCreate()", err, err != PRO_TK_NO_ERROR);
    ProMenuDelete();
    return (0);
}



/*====================================================================*\
FUNCTION : ProUtilFeatPatternClass
PURPOSE  : Return the pattern class the feature belongs to
\*====================================================================*/
ProError ProUtilFeatPatternClass(
    ProFeature *feature,
    ProPatternClass *pat_class)
{
    ProGrppatternStatus grpat_status;
    ProPatternStatus	pat_status;
    ProError err;
    
    err = ProFeaturePatternStatusGet(feature, &pat_status);
    TEST_CALL_REPORT("ProFeaturePatternStatusGet()",
		"ProUtilFeatPatternClass()", err , err != PRO_TK_NO_ERROR);

    err = ProFeatureGrppatternStatusGet(feature, &grpat_status);
    TEST_CALL_REPORT("ProFeatureGrppatternStatusGet()",
		"ProUtilFeatPatternClass()", err , err != PRO_TK_NO_ERROR);

    if (pat_status == PRO_PATTERN_LEADER || pat_status == PRO_PATTERN_MEMBER)
    {
	if (grpat_status == PRO_GRP_PATTERN_LEADER || 
	    grpat_status == PRO_GRP_PATTERN_MEMBER)
	{
	    /* Both Patterns Possible */
	    err = ProMenuFileRegister((char*)"tkpat type", (char*)"tkpattype.mnu", NULL);
	    err = ProMenubuttonActionSet((char*)"tkpat type", (char*)"Pattern",
		(ProMenubuttonAction)ProUtilMenubuttonDeleteWithStatus, NULL, PRO_FEAT_PATTERN);
	    err = ProMenubuttonActionSet((char*)"tkpat type", (char*)"Group Pattern",
		(ProMenubuttonAction)ProUtilMenubuttonDeleteWithStatus, NULL, PRO_GROUP_PATTERN);
	    err = ProMenubuttonActionSet((char*)"tkpat type", (char*)"tkpat type",
		(ProMenubuttonAction)ProMenuHold, NULL, 0);

	    err = ProMenuCreate(PROMENUTYPE_MAIN, (char*)"tkpattype", NULL);
	    err = ProMenuProcess((char*)"tkpattype", (int*)pat_class);
	} 
	else
	    pat_class[0] = PRO_FEAT_PATTERN;  
    }
    else
    {
	if (grpat_status == PRO_GRP_PATTERN_LEADER || 
	    grpat_status == PRO_GRP_PATTERN_MEMBER)
	    pat_class[0] = PRO_GROUP_PATTERN;  
	else
	    return (PRO_TK_E_NOT_FOUND);
    }
    return (PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestPattern
PURPOSE  : Function to test pattern functions
\*====================================================================*/
int ProTestPattern(    
    ProSolid *p_solid)
{
    ProError err;
    ProFeature feature;
    ProPatternClass pat_class;
    ProPattern pattern;
    ProElement elemtree;
    ProSelection *p_sel;
    int n_sel;

    ProUtilMsgPrint("feat", "TEST Select feature");    
    
    err = ProSelect((char*)"feature", 1, NULL, NULL, NULL, NULL, &p_sel, &n_sel);
    if (err != PRO_TK_NO_ERROR || n_sel != 1)
	return (0);
    err = ProSelectionModelitemGet(p_sel[0],
                          (ProModelitem *)&feature);
    TEST_CALL_REPORT("ProSelectionModelitemGet()",
		"ProTestPatternTreeInfoGet", err , err != PRO_TK_NO_ERROR);


    err = ProUtilFeatPatternClass(&feature, &pat_class);
    if (err != PRO_TK_NO_ERROR)
    {
	ProUtilMsgPrint("gen","TEST %0s",
	    "This feature does not belong to the pattern.");
    }
    else
    {
        /* Get the leader feature */
        err = ProFeaturePatternGet( &feature, pat_class, &pattern );
        TEST_CALL_REPORT("ProFeaturePatternGet()",
                "ProTestPattern", err , err != PRO_TK_NO_ERROR);
        err = ProPatternLeaderGet( &pattern, &feature );
        TEST_CALL_REPORT("ProPatternLeaderGet",
                "ProTestPattern", err , err != PRO_TK_NO_ERROR);

        err = ProPatternElemtreeCreate(&feature, pat_class, &elemtree );
        TEST_CALL_REPORT("ProPatternElemtreeCreate()",
                "ProTestPattern", err , err != PRO_TK_NO_ERROR);
	
	switch (err)
	  {
	  case PRO_TK_NOT_IMPLEMENTED:
	    ProUtilMsgPrint ("feat", "TEST %0s", "Selected pattern is a fill pattern.  Fill patterns are not currently supported via element trees.");
	    break;
	  case PRO_TK_NO_ERROR:
	      ProUtilShowTreeInInfo(elemtree);

	      err = ProElementFree(&elemtree);
	      TEST_CALL_REPORT("ProElementFree()",
			       "ProTestPattern", err , err != PRO_TK_NO_ERROR);
	      break;
	  default:
	    ProUtilMsgPrint("feat", "TEST %0s", "Error getting the elem tree");
	    break;
	}
    }

    return(PRO_TK_NO_ERROR);
}



/*====================================================================*\
    FUNCTION :	ProTestFeatures()
    PURPOSE  :	Test code for features
\*====================================================================*/
int ProTestFeatures(
    ProMdl *model)
{
    ProError		status;
    int			menu_id;    /* The identifier of the created menu */
    int			action;

    /* Load menu from file */
    status = ProMenuFileRegister( (char*)"TkFeats", (char*)"tkfeats.mnu", &menu_id );
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestFeatures()", 
			status, status != PRO_TK_NO_ERROR );

    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Create",
        (ProMenubuttonAction)ProTestFeatCreate, model, 0 );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Create Pattern",
        (ProMenubuttonAction)ProTestPatternCreate, NULL, 0 );        
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Tree Info", 
	(ProMenubuttonAction)ProTestFeatTreeInfoGet, model, 0 );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Model Info", 
	(ProMenubuttonAction)ProTestFeatureInfo, model, MODEL_INFO );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Feat Info", 
	(ProMenubuttonAction)ProTestFeatureInfo, model, FEAT_INFO );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Feat List", 
	(ProMenubuttonAction)ProTestFeatureInfo, model, FEAT_LIST );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Sect Info",
	(ProMenubuttonAction)ProTestFeatureSectionInfo, model, 0 );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Delete", 
	(ProMenubuttonAction)ProTestFeatureKill, model, DELETE );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Pattern", 
	(ProMenubuttonAction)ProTestPattern, model, 0);
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Group", 
	(ProMenubuttonAction)ProTestLocalGroupCreate, model, 0 );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Suppress", 
	(ProMenubuttonAction)ProTestFeatureKill, model, SUPPRESS );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Resume", 
	(ProMenubuttonAction)ProTestFeatureResume, model, RESUME );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Reorder", 
	(ProMenubuttonAction)ProTestFeatureReorder, model, 0);
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Read Only", 
	(ProMenubuttonAction)ProTestFeatureReadOnly, model, 0);
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Insert mode", 
	(ProMenubuttonAction)ProTestFeatureInsertMode, model, 0);
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"-Done TkFeats", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0 );
    ProMenubuttonActionSet( (char*)"TkFeats", (char*)"TkFeats", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0 );

    /* Run menu TkFeats */
    status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkFeats", &menu_id );
    TEST_CALL_REPORT( "ProMenuCreate()", "ProTestFeatures()", 
			status, status != PRO_TK_NO_ERROR );
    if( status == PRO_TK_NO_ERROR )
    {
	status = ProMenuProcess( (char*)"TkFeats", &action );
	TEST_CALL_REPORT( "ProMenuProcess()", "ProTestFeatures()", 
			    status, status != PRO_TK_NO_ERROR );
    }

    return(0);
}

#undef FEAT_LIST
#undef FEAT_INFO
#undef MODEL_INFO
#undef	DELETE
#undef SUPPRESS
#undef RESUME

#undef USER_SELECT
#undef USER_FEAT_NUM
#undef USER_ALL_FEAT
#undef USER_CLEAN

#undef USER_ACTIVATE
#undef USER_CANCEL

#undef USER_BEFORE
#undef USER_AFTER