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


/*--------------------------------------------------------------------*\
Pro/Toolkit  includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProElement.h>
#include <ProFeature.h>
#include <ProSelection.h>
#include <ProNcseq.h>
#include <ProNcseqElem.h>
#include <ProMenu.h>
#include <ProPecktable.h>
#include <ProTKRunTime.h>
#include <ProModelitem.h>
#include <ProUtil.h>
#include <ProModelitem.h>
#include <PTApplsUnicodeUtils.h>
#include <ProMessage.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "MfgMenu.h"
#include "TestConsts.h"
#include "UtilString.h"
#include "UtilGeom.h"
#include "TestError.h"
#include "UtilTree.h"
#include "TestMfgNew.h"
#include "UtilMfgNew.h"
#include "UtilMenu.h"
#include "UtilMessage.h"

#include <ctype.h>

#define BLIND_SURFACE 0
#define BLIND_ENTER   1

#define DRILL_STANDART	0
#define DRILL_DEEP	1
#define DRILL_CSINK	2

typedef struct
{
    int n_ranges;
    struct
    {
        double  low_dia, high_dia;
        int     n_pecks;
        double  peck_depth_ratios[5];
        double  feed_rates[5];
    }ranges[2];
}PecktableData;

/*--------------------------------------------------------------------*\
Function prototypes
\*--------------------------------------------------------------------*/
static ValueType parse_string( const char *s, char *out);


/*====================================================================*\
FUNCTION : ProUtilMfgobjAction
PURPOSE  : List features of specified type and call the supplied
           function for each feature type
\*====================================================================*/
ProError ProUtilMfgobjAction ( 
    MfgMenuChoice *obj_action, 
    int            obj_type,
    int            max_sels,
    MfgActionFunc  func,
    ProAppData     app_data,
    int            int_val)
{
    wchar_t **menu_items, **selected;
    wchar_t   wtitle[PRO_NAME_SIZE], item_name[PRO_NAME_SIZE];
    char      title[] = "TK_MFG_FEATS", obj_name[PRO_NAME_SIZE];
    int       i,j, num_selected, num_objs;
    ProError status = PRO_TK_NO_ERROR;
    ProModelitem   *mdl_item = NULL;
    ProTool        *tool_item = NULL;
     
/*--------------------------------------------------------------------*\
    Initial input checking
\*--------------------------------------------------------------------*/
    if (obj_action == NULL || obj_action->mfgobj_list == NULL || 
					func == (MfgActionFunc) NULL )
	status = PRO_TK_BAD_INPUTS;
    
    if (status == PRO_TK_NO_ERROR)
    {
	switch ( obj_type )
	{
	    case MFGOBJ_WKCELL:
	        num_objs = obj_action->mfgobj_list->n_wcell;
		mdl_item = obj_action->mfgobj_list->wcell;
		break;
	    case MFGOBJ_OPER:
	        num_objs = obj_action->mfgobj_list->n_oper;
		mdl_item = obj_action->mfgobj_list->oper;
		break;
	    case MFGOBJ_NC_SEQ:
	        num_objs = obj_action->mfgobj_list->n_nc_seq;
		mdl_item = obj_action->mfgobj_list->nc_seq;
		break;
	    case MFGOBJ_FIXTURE:
	        num_objs = obj_action->mfgobj_list->n_fixture;
		mdl_item = obj_action->mfgobj_list->fixture;
		break;
	    case MFGOBJ_TOOL:
	        num_objs = obj_action->mfgobj_list->n_tool;
		tool_item = obj_action->mfgobj_list->tool;
		break;
	    default :
		status = PRO_TK_BAD_INPUTS;
	}
    }

    if (status != PRO_TK_NO_ERROR)
	return status;

    ProTKFprintf(stderr, (char*)" Number of objects = %d \n", num_objs );
    ProTKFprintf(stderr, (char*)" Modelitem ptr     = %x \n", mdl_item );


/*--------------------------------------------------------------------*\
    Allocate space for strings array ( add one item for empty string )
\*--------------------------------------------------------------------*/
    menu_items = (wchar_t **) calloc ( num_objs + 1, sizeof(wchar_t *));
    
    if ( menu_items == NULL)
	status = PRO_TK_GENERAL_ERROR;

    for ( i = 0; i < num_objs && status == PRO_TK_NO_ERROR ; i++)
    {
	menu_items[i] = (wchar_t*) calloc (PRO_NAME_SIZE,sizeof(wchar_t));
	if ( menu_items[i] == NULL)
	    status = PRO_TK_GENERAL_ERROR;

        if ( status == PRO_TK_NO_ERROR)
	{
	    if (tool_item != NULL)
	    {
		ProUtilWstrcpy( menu_items[i], (wchar_t*) tool_item[i].tool_id); 
	    }
	    else
	    {
		status = ProModelitemNameGet ( &(mdl_item[i]), menu_items[i]);
		TEST_CALL_REPORT("ProModelitemNameGet()",
			         "ProUtilMfgobjAction()",
				  status, status != PRO_TK_NO_ERROR );
	    }
	}
    }

    for (i= 0 ; i < num_objs ; i++)
    {
	ProWstringToString(obj_name, menu_items[i]);
        ProTKFprintf(stderr,(char*)"Menu item [%d] = %s\n", i, obj_name); 
    }

    if (status == PRO_TK_NO_ERROR)
    {
/*--------------------------------------------------------------------*\
	Add a blank line
\*--------------------------------------------------------------------*/
        menu_items[num_objs] = (wchar_t*) calloc (1, sizeof(wchar_t));
	ProStringToWstring(menu_items[num_objs],(char*)"");

/*--------------------------------------------------------------------*\
	Get selections
\*--------------------------------------------------------------------*/
	status = ProMenuStringsSelect(ProStringToWstring(wtitle,title),
		    menu_items, max_sels, NULL, &selected, &num_selected);  
	TEST_CALL_REPORT("ProMenuStringsSelect()", "ProUtilMfgobjAction()",
					status, status != PRO_TK_NO_ERROR );
    }
    
/*--------------------------------------------------------------------*\
    Call func for each of the features selected
\*--------------------------------------------------------------------*/
    if ( status == PRO_TK_NO_ERROR && num_selected > 0 )
    {
	for ( i = 0; status == PRO_TK_NO_ERROR &&  i < num_selected; i++)
	{

	    for ( j = 0; j < num_objs; j++)
	    {
	    
		if (tool_item != NULL)
		{
		    ProUtilWstrcpy( item_name, tool_item[j].tool_id);
		}
		else
		{
		    status = ProModelitemNameGet ( &(mdl_item[j]), item_name);
		    TEST_CALL_REPORT("ProModelitemNameGet()",
					"ProUtilMfgobjAction()",
					status, status != PRO_TK_NO_ERROR );
		}

		if (!ProUtilWstrCmp ( item_name, selected[i] ))
		{
		    if ( tool_item != NULL)
		    {
			status = func((ProAppData) &(tool_item[j]), 
							app_data, int_val);
		    }
		    else
		    {
			status = func((ProAppData) &(mdl_item[j]), 
							app_data, int_val);
		    }
		    break;
		}
	    }
	}
    }
    
    for (i= 0 ; i < num_objs + 1; i++)
    {
	free(menu_items[i]);
    }

    free(menu_items);

    return status;
}

/*====================================================================*\
FUNCTION : ProUtilElementBuild
PURPOSE  : Given a value type and a value return the element
\*====================================================================*/
ProError ProUtilElementBuild (
    ProValueDataType data_type,
    void            *data,
    ProElement      *element)
{
    ProError status = PRO_TK_NO_ERROR;
    ProSelection *s;
    int *i;
    double *d;
    char *c;
    wchar_t *w;
	ProReference ref;

    switch (data_type)
    {
	case PRO_VALUE_TYPE_INT:
	    i = (int*) data;
		status = ProElementIntegerSet(*element, *i);
	    TEST_CALL_REPORT("ProElementIntegerSet()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));
	    break;
	case PRO_VALUE_TYPE_DOUBLE:
	    d = (double*) data;
		status = ProElementDoubleSet(*element, *d);
	    TEST_CALL_REPORT("ProElementDoubleSet()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));
	    break;
	case PRO_VALUE_TYPE_STRING:
		c = (char*) data;
				status = ProElementStringSet(*element, c);
	    TEST_CALL_REPORT("ProElementStringSet()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));
	    break;
	case PRO_VALUE_TYPE_WSTRING:
		w = (wchar_t*) data;    
		status = ProElementWstringSet(*element, w);
	    TEST_CALL_REPORT("ProElementWstringSet()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));
	    break;
	case PRO_VALUE_TYPE_SELECTION:
		s = (ProSelection*) data;

		status = ProSelectionToReference(*s, &ref);
		TEST_CALL_REPORT("ProSelectionToReference()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));

		 status = ProElementReferenceSet(*element, ref);
	    TEST_CALL_REPORT("ProElementReferenceSet()","ProUtilElementBuild()",
				    status, (status != PRO_TK_NO_ERROR));
	    break;
        default:
	    break;
    }
    return status;
}

/*====================================================================*\
FUNCTION : ProTestWcParamSetup
PURPOSE  : Set a couple of wc parameters
\*====================================================================*/
ProError ProTestWcParamSetup( ProElement *wc_elem )
{
    ProError status = PRO_TK_NO_ERROR;
    ProElement wc_param, name_elem, value_elem;
    ParamTable wc_params[] = {{"CELL_MAX_SPINDLE", 1800.0 },
                              {"TOOL_CHANGE_TIME", 1.0    },
              	              {"CELL_MAX_FEED",    300.0  }};
    int wc_param_size = sizeof(wc_params)/sizeof(ParamTable), i;

    for (i = 0; i < wc_param_size; i++)
    {
	status = ProElementAlloc(PRO_E_MFG_PARAM, &wc_param);

        if (status == PRO_TK_NO_ERROR)
	    status = ProElementAlloc(PRO_E_MFG_PARAM_NAME, &name_elem);
	
        if (status == PRO_TK_NO_ERROR)
	{
	    status = ProUtilElementBuild(PRO_VALUE_TYPE_STRING, 
	    			wc_params[i].param_name, &name_elem); 
	}

        if (status == PRO_TK_NO_ERROR)
	    status = ProElementAlloc(PRO_E_MFG_PARAMVAL, &value_elem);

        if (status == PRO_TK_NO_ERROR)
	    status = ProUtilElementBuild(PRO_VALUE_TYPE_DOUBLE,
	    			&(wc_params[i].paramval), &value_elem);
	
        if (status == PRO_TK_NO_ERROR)
            status = ProElemtreeElementAdd(wc_param, NULL, name_elem);
	    
        if (status == PRO_TK_NO_ERROR)
            status = ProElemtreeElementAdd(wc_param, NULL, value_elem);
	
        if (status == PRO_TK_NO_ERROR)
	    status = ProElemtreeElementAdd(*wc_elem, NULL, wc_param);
    }

    return status;
}

/*====================================================================*\
Function: ProTestCreateSelection
Purpose : Creates a selection structure used in feature creation
\*====================================================================*/
ProError  ProTestCreateSelection(
    int item_id, 
    ProType item_type, 
    ProSelection *p_selection)
{
    ProError status;
    ProMfg mfg_model;
    ProSolid mfg_solid;
    ProAsmcomppath comp_path;
    ProModelitem wkpiece_item;

    ProType type;
 
    status = PRO_TK_NO_ERROR;
 
    status = ProTestGetModels( &mfg_model, &mfg_solid, &comp_path);
    ProMdlTypeGet(mfg_model, (ProMdlType *) &type);
    ProTKPrintf((char*)"Mfg solid type (%d)\n", type);

    status = ProModelitemInit( mfg_solid, item_id, item_type, &wkpiece_item );
    TEST_CALL_REPORT("ProModelitemInit()",
	"ProTestCreateWkcell()", status,
	(status != PRO_TK_NO_ERROR));

    status = ProSelectionAlloc(&comp_path, &wkpiece_item, p_selection);
	
    TEST_CALL_REPORT("ProSelectionAlloc()",
		"ProTestCreateSelection()", status,
		(status != PRO_TK_NO_ERROR));

    return ( status );
}

/*====================================================================*\
FUNCTION   : ProTestGetModels
PURPOSE    : Retrieves structures for mfg_model, solid and component path
PT_KEYWORD : retrieve, model, component path
PT_SEEALSO : ProAsmcompTypeGet, ProMdlCurrentGet
\*====================================================================*/
ProError ProTestGetModels(
    ProMfg *p_mfg_model, 
    ProSolid *p_mfg_solid, 
    ProAsmcomppath *p_comp_path)
{ 
    ProError status;
    ProMdlType mfg_model_type;

    status = ProMdlCurrentGet((ProMdl *)p_mfg_model);
    TEST_CALL_REPORT("ProMdlCurrentGet()",
                "ProTestGetModels()", status,
                (status != PRO_TK_NO_ERROR));

    ProMdlTypeGet(*p_mfg_model, &mfg_model_type);
    if ( mfg_model_type == PRO_MDL_MFG )
    {
	if (status == PRO_TK_NO_ERROR )
	{
	    status = ProMfgSolidGet(*p_mfg_model, p_mfg_solid);
            TEST_CALL_REPORT("ProMfgSolidGet()",
                "ProTestGetModels()", status,
                (status != PRO_TK_NO_ERROR));

	    if (status == PRO_TK_NO_ERROR)
	    {
		status= ProMfgFeatureOwnerGet(*p_mfg_model, p_comp_path);
                TEST_CALL_REPORT("ProMfgFeatureOwnerGet()",
               		 "ProTestGetModels()", status,
               		 (status != PRO_TK_NO_ERROR));
	    }
	}
    }    
    else
    {
	status = PRO_TK_BAD_CONTEXT;
    }

  return(status);
}

/*====================================================================*\
FUNCTION : ProTestDepTypeAction
PURPOSE  : Action function for Depth type menu
\*====================================================================*/
int ProTestDepTypeAction(
    void* p_dummy, 
    int action )
{
    ProError status;
    status = ProMenuDeleteWithStatus (action);
    return (status);
}

/*====================================================================*\
FUNCTION : ProTestSelectionPostSelact
PURPOSE  : Selection post selaction
\*====================================================================*/
ProError ProTestSelectionPostSelact(
         Pro3dPnt point,
         ProSelection selection,
         ProAppData app_data)
{
    TEST_CALL_REPORT ("ProSelectionPostSelact()", 
        "ProTestSelectionPostSelact()",
        PRO_TK_NO_ERROR, 0);
    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProUtilNcseqElemMillsurfSet
PURPOSE  : Add milling surface to the element (PRO_E_SURFACES).
\*====================================================================*/
ProError ProUtilNcseqElemMillsurfSet (
    ProElement *surfaces )
{
    ProError err;
	int mill_srf_id;
	ProBoolean  flip;

	static ProUtilMenuButtons set_flip[] = {
	{"TkSetFlip", 0, TEST_CALL_PRO_MENU_DELETE},
	{"Flip", PRO_B_TRUE, 0 },
	{"Natural", PRO_B_FALSE, 0 },
	{"",0,0}
    };

	if (ProUtilIntGet(NULL, NULL, &mill_srf_id) == 0)
	{
		return PRO_TK_MSG_USER_QUIT;
	}

	err = ProUtilMenuIntValueSelect(set_flip, (int *)&flip);
	
	if (err != PRO_TK_NO_ERROR)
	     return (PRO_TK_MSG_USER_QUIT);

	err =  ProNcseqElemMillsurfSet (*surfaces, flip, mill_srf_id);
	TEST_CALL_REPORT("ProNcseqElemMillsurfSet()",
			 "ProUtilNcseqElemMillsurfSet()", err,
                          (err != PRO_TK_NO_ERROR));
	return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION : ProUtilNcseqElemVolumeSet
PURPOSE  : Add a volume to the element (PRO_E_SURFACES, PRO_E_VOLUME).
\*====================================================================*/
ProError ProUtilNcseqVolumeSet (
    ProElement *surfaces )
{
    ProError err;
	int volume_id;


	if (ProUtilIntGet(NULL, NULL, &volume_id) == 0)
	{
		return PRO_TK_MSG_USER_QUIT;
	}

	err =  ProNcseqElemVolumeSet (*surfaces, volume_id  );
	TEST_CALL_REPORT("ProNcseqElemVolumeSet()",
			 "ProUtilNcseqVolumeSet()", err,
                          (err != PRO_TK_NO_ERROR));
	return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION : ProUtilNcseqElemWindowSet
PURPOSE  : Add a window to the element (PRO_E_MACH_WINDOW).
\*====================================================================*/
ProError ProUtilNcseqWindowSet (
    ProElement *mach_wnd )
{
    ProError err;
	int wind_id;


	if (ProUtilIntGet(NULL, NULL, &wind_id) == 0)
	{
		return PRO_TK_MSG_USER_QUIT;
	}

	err =  ProNcseqElemWindowSet (*mach_wnd, wind_id  );
	TEST_CALL_REPORT("ProNcseqElemWindowSet()",
			 "ProUtilNcseqWindowSet()", err,
                          (err != PRO_TK_NO_ERROR));
	return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION : ProUtilNcseqStartEndPntSet
PURPOSE  : Adds start or end pont to the element (PRO_E_START, PRO_E_END).
\*====================================================================*/
ProError ProUtilNcseqStartEndPntSet (
    ProElement *start_end )
{
    ProError err;
    ProMachHead    head;
    ProSelection * point;
    int n_sel;
    ProElemId start_or_end;

/*----------------------------------------------------------------------*\
  select a point
\*----------------------------------------------------------------------*/

   err = ProSelect((char*)"point", 1, NULL, NULL, NULL, NULL,
	    &point, &n_sel);
   TEST_CALL_REPORT("ProSelect()", 
	    "ProUtilNcseqStartEndPntSet()", err, err != PRO_TK_NO_ERROR);
   if (err != PRO_TK_NO_ERROR)
	    return (PRO_TK_MSG_USER_QUIT);
/*----------------------------------------------------------------------*\
  select a head
\*----------------------------------------------------------------------*/
   
   
	if (ProUtilIntGet(NULL, NULL, (int*)&head) == 0)
	{
		return PRO_TK_MSG_USER_QUIT;
	}

	err = ProElementIdGet (*start_end, &start_or_end);
	TEST_CALL_REPORT("ProElementIdGet()",
			 "ProUtilNcseqStartEndPntSet()", err,
                          (err != PRO_TK_NO_ERROR));
	if (start_or_end == PRO_E_START)
	{
		err = ProNcseqElemStartPntSet (*start_end,
			head, point[0]);
		TEST_CALL_REPORT("ProNcseqElemStartPntSet()",
			 "ProUtilNcseqStartEndPntSet()", err,
                          (err != PRO_TK_NO_ERROR));
		return PRO_TK_NO_ERROR;
	}

	if (start_or_end == PRO_E_END)
	{
		err = ProNcseqElemEndPntSet (*start_end,
			head, point[0]);
		TEST_CALL_REPORT("ProNcseqElemEndPntSet()",
			 "ProUtilNcseqStartEndPntSet()", err,
                          (err != PRO_TK_NO_ERROR));
		return PRO_TK_NO_ERROR;
	}

		
	return PRO_TK_BAD_INPUTS;
}	

/*====================================================================*\
FUNCTION : ProUtilNcseqElemSurfacesAdd
PURPOSE  : Add surfaces to element
NOTE     : Surfaces must be added using the api function
\*====================================================================*/
ProError ProUtilNcseqElemSurfacesAdd (
    ProElement *surfaces )
{
    ProError      status;
    ProSelection *selection;
    int           num_selected, i, action, menu_id;
    ProModelitem  modelitem;
    
    status = ProSelect((char*)"surface", -1, NULL, NULL, NULL, NULL, 
				    &selection, &num_selected);
    TEST_CALL_REPORT("ProSelect()", "ProUtilNcseqElemSurfacesAdd()", 
    				status, status != PRO_TK_NO_ERROR);
	
	if (num_selected == 0 && status == PRO_TK_NO_ERROR)
	{
		 status = ProUtilNcseqElemMillsurfSet(surfaces);
		 if (status == PRO_TK_MSG_USER_QUIT)
			 status = ProUtilNcseqVolumeSet(surfaces);
		 return status;
	}

    for (i=0; i<num_selected; i++)
    {
	status = ProNcseqElemSurfaceAdd(*surfaces, selection[i]);
	TEST_CALL_REPORT("ProNcseqElemSurfaceAdd()",
			 "ProUtilNcseqElemSurfacesAdd()", status,
                          (status != PRO_TK_NO_ERROR));
        
        status = ProSelectionModelitemGet (selection[i], &modelitem);
        TEST_CALL_REPORT( "ProSelectionModelitemGet()", 
            "ProUtilNcseqElemSurfacesAdd()", 
	    status, status != PRO_TK_NO_ERROR );

        status = ProMenuFileRegister( (char*)"TkDirect", (char*)"tkdepdirect.mnu", &menu_id );
        TEST_CALL_REPORT( "ProMenuFileRegister()", 
            "ProUtilNcseqElemSurfacesAdd()", 
	    status, status != PRO_TK_NO_ERROR );

        /* Define menu buttons */
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"Natural",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_B_FALSE);
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"Flip",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_B_TRUE);
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"TkDirect", 
            (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
        status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDirect", &menu_id );
        TEST_CALL_REPORT( "ProMenuCreate()", "ProUtilNcseqElemSurfacesAdd()", 
			status, status != PRO_TK_NO_ERROR );
        if( status == PRO_TK_NO_ERROR )
        {
            status = ProMenuProcess( (char*)"TkDirect", &action );
            TEST_CALL_REPORT( "ProMenuProcess()", "ProUtilNcseqElemSurfacesAdd()", 
	        status, status != PRO_TK_NO_ERROR );
        }
        status = ProNcseqElemSurfaceflipSet (*surfaces, (ProBoolean)action);
        TEST_CALL_REPORT("ProNcseqElemSurfaceflipSet()",
			 "ProUtilNcseqElemSurfacesAdd()", status,
                          (status != PRO_TK_NO_ERROR));
    }

    return status;
}


/*====================================================================*\
FUNCTION : ProTestPecktabledataSet
PURPOSE  : Fills ProPecktableData structure
\*====================================================================*/
ProError ProTestPecktabledataSet(ProPecktableData *p_pecktable_data)
{
    int i, j, n_ranges = 0;
    FILE *fp;
    float peck_depth_ratios; 
    float feed_rates;
    int ranges_size[50];
    char cstr[80];
    float low_dia, high_dia;
    
    if ((fp = PTApplsUnicodeFopen ("pecktable.pec", "rt")) == NULL)
        return (PRO_TK_GENERAL_ERROR);

    ranges_size[n_ranges] = 0;  
    for (i = 0; fgets (cstr, PRO_PATH_SIZE, fp) != NULL; i++)
    {
         if (cstr[0] == '\0')
             break;
         sscanf (cstr, "%f %f %f %f", &low_dia, &high_dia,
             &peck_depth_ratios, &feed_rates);
         if (low_dia > 0.0)
         {
             ranges_size[n_ranges] = 0;
             n_ranges++;            
         }
         ranges_size[n_ranges-1]++;
    }
    
    fclose (fp);

    p_pecktable_data->n_ranges = n_ranges;
    p_pecktable_data->ranges = (ProPecktableRange*)calloc (
        n_ranges, sizeof (ProPecktableRange));
    
    
    if ((fp = PTApplsUnicodeFopen ("pecktable.pec", "rt")) == NULL)
        return (PRO_TK_GENERAL_ERROR);
      
    for (i = 0, j = 0; fgets (cstr, PRO_PATH_SIZE, fp) != NULL; i++)
    {
         sscanf (cstr, "%f %f %f %f", &low_dia, &high_dia,
             &peck_depth_ratios, &feed_rates);
         if (low_dia > 0.0 && high_dia > 0.0)
         {
             p_pecktable_data->ranges[j].n_pecks = ranges_size[j];
             p_pecktable_data->ranges[j].low_dia = low_dia;
             p_pecktable_data->ranges[j].high_dia = high_dia;
             p_pecktable_data->ranges[j].peck_depth_ratios = 
                 (double*)calloc (ranges_size[j], sizeof (double));
             p_pecktable_data->ranges[j].feed_rates = 
                 (double*)calloc (ranges_size[j], sizeof (double));
             j++;
             i = 0;
         }
         p_pecktable_data->ranges[j-1].peck_depth_ratios[i] = 
             peck_depth_ratios;
         p_pecktable_data->ranges[j-1].feed_rates[i] = 
             feed_rates;
    }
    
    fclose (fp);
       
    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProUtilNcseqElemHolesAdd
PURPOSE  : Add holes to element
NOTE     : Holes must be added using the api function
\*====================================================================*/
ProError ProUtilNcseqElemHolesAdd (
    ProElement *holes )
{
    ProError status;
    int      set_nmb, num_selected, i;
    ProSelection *p_selection, *start_sels;
    int menu_id, action, blind_action = BLIND_SURFACE, drill_action = DRILL_STANDART;
    double depth, csink;
    ProMfgType type;
    ProMfg mfg_model;
    ProPecktable peck_table;
    ProPecktableData pecktable_data;
    
        status = ProMdlCurrentGet ((ProMdl*)&mfg_model);
        TEST_CALL_REPORT("ProMdlCurrentGet()",
            "ProTestCreateHoleMkNCseq()", status,
            (status != PRO_TK_NO_ERROR));
    
        status = ProMenuFileRegister( (char*)"TkDrillType", (char*)"tkdrilltype.mnu", &menu_id );
        TEST_CALL_REPORT( "ProMenuFileRegister()", 
            "ProTestCreateHoleMkNCseq()", 
	    status, status != PRO_TK_NO_ERROR );

        /* Define menu buttons */
        ProMenubuttonActionSet( (char*)"TkDrillType", (char*)"Standart",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, DRILL_STANDART);
        ProMenubuttonActionSet( (char*)"TkDrillType", (char*)"Deep",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, DRILL_DEEP);
        ProMenubuttonActionSet( (char*)"TkDrillType", (char*)"Countersink",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, DRILL_CSINK);
        ProMenubuttonActionSet( (char*)"TkDrillType", (char*)"TkDrillType", 
            (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
        status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDrillType", &menu_id );
        TEST_CALL_REPORT( "ProMenuCreate()", "ProTestCreateHoleMkNCseq()", 
			status, status != PRO_TK_NO_ERROR );
        if( status == PRO_TK_NO_ERROR )
        {
            status = ProMenuProcess( (char*)"TkDrillType", &drill_action );
            TEST_CALL_REPORT( "ProMenuProcess()", "ProTestCreateHoleMkNCseq()", 
	        status, status != PRO_TK_NO_ERROR );
        }
        if (drill_action == DRILL_DEEP)
        {
            if (ProTestPecktabledataSet (&pecktable_data) == PRO_TK_NO_ERROR)
            {
                status = ProPecktableCreate ((ProPecktableData*)
                    &pecktable_data, &peck_table);
                TEST_CALL_REPORT( "ProPecktableCreate()", 
                    "ProTestCreateHoleMkNCseq()", 
                    status, status != PRO_TK_NO_ERROR );
                status = ProMfgPecktableSet (mfg_model, 
                    (ProConstPecktable)peck_table);
                TEST_CALL_REPORT( "ProMfgPecktableSet()", 
                    "ProTestCreateHoleMkNCseq()", 
                    status, status != PRO_TK_NO_ERROR );
                status = ProPecktableFree (peck_table);
                TEST_CALL_REPORT( "ProPecktableFree()", 
                    "ProTestCreateHoleMkNCseq()", 
                    status, status != PRO_TK_NO_ERROR );
            }
        }
  
        status = ProNcseqElemHolesetAdd( *holes, &set_nmb);
        TEST_CALL_REPORT("ProNcseqElemHolesetAdd()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));

        status = ProSelect((char*)"axis", -1,
                      NULL, NULL, NULL, NULL, &p_selection, &num_selected);
        TEST_CALL_REPORT("ProSelect()", "ProTestCreateHoleMkNCseq()", status,
                        status != PRO_TK_NO_ERROR);
        for (i=0; i<num_selected; i++)
        {
            status = ProNcseqElemHolesetAxisAdd( *holes,
                                      set_nmb, p_selection[i]);
            TEST_CALL_REPORT("ProNcseqElemHolesetAxisAdd()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
        }

	   
	
/*--------------------------------------------------------------------*\
        Set the holeset depth type (can be _BLIND, _THRU_ALL or _AUTO)
\*--------------------------------------------------------------------*/
        status = ProMenuFileRegister( (char*)"TkDepType", (char*)"tkdeptype.mnu", &menu_id );
        TEST_CALL_REPORT( "ProMenuFileRegister()", 
            "ProTestCreateHoleMkNCseq()", 
	    status, status != PRO_TK_NO_ERROR );

        /* Define menu buttons */
        ProMenubuttonActionSet( (char*)"TkDepType", (char*)"Blind",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_DRILL_BLIND);
        ProMenubuttonActionSet( (char*)"TkDepType", (char*)"Thru all",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_DRILL_THRU_ALL);
        ProMenubuttonActionSet( (char*)"TkDepType", (char*)"Auto",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_DRILL_AUTO);
        ProMenubuttonActionSet( (char*)"TkDepType", (char*)"TkDepType", 
            (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
        status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDepType", &menu_id );
        TEST_CALL_REPORT( "ProMenuCreate()", "ProTestCreateHoleMkNCseq()", 
			status, status != PRO_TK_NO_ERROR );
        if( status == PRO_TK_NO_ERROR )
        {
            status = ProMenuProcess( (char*)"TkDepType", &action );
            TEST_CALL_REPORT( "ProMenuProcess()", "ProTestCreateHoleMkNCseq()", 
	        status, status != PRO_TK_NO_ERROR );
        } 
        else
            action = PRO_DRILL_AUTO;
            
        status = ProNcseqElemHolesetDepthTypeSet( *holes, set_nmb, (ProDrillDepthType)action);
        TEST_CALL_REPORT("ProNcseqElemHolesetDepthTypeSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
        
        if (action == PRO_DRILL_BLIND ||
            drill_action == DRILL_CSINK)
        {
            ProUtilMsgPrint ((char*)"gen", (char*)"TEST %0s", 
                "Select start surface or datum plane");
            status = ProSelect((char*)"surface,datum", 1,
                      NULL, NULL, NULL, NULL, &start_sels, &num_selected);
            TEST_CALL_REPORT("ProSelect()", "ProTestCreateHoleMkNCseq()", 
                status, status != PRO_TK_NO_ERROR);
            if (status != PRO_TK_NO_ERROR || num_selected != 1)
                return ((ProError)0);
            status = ProNcseqElemHolesetStartSet (*holes, 
                set_nmb, start_sels[0]);
            TEST_CALL_REPORT("ProNcseqElemHolesetStartSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
        }
        
        if (action == PRO_DRILL_BLIND)
        {
            status = ProMenuFileRegister( (char*)"TkDepBlind", (char*)"tkdepblind.mnu", &menu_id );
            TEST_CALL_REPORT( "ProMenuFileRegister()", 
                "ProTestCreateHoleMkNCseq()", 
                status, status != PRO_TK_NO_ERROR );

            /* Define menu buttons */
            ProMenubuttonActionSet( (char*)"TkDepBlind", (char*)"Surface",
                (ProMenubuttonAction)ProTestDepTypeAction, NULL, 
                BLIND_SURFACE);
            ProMenubuttonActionSet( (char*)"TkDepBlind", (char*)"Enter",
                (ProMenubuttonAction)ProTestDepTypeAction, NULL, 
                BLIND_ENTER);
            ProMenubuttonActionSet( (char*)"TkDepBlind", (char*)"TkDepBlind", 
                (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
            status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDepBlind", &menu_id );
            TEST_CALL_REPORT( "ProMenuCreate()", "ProTestCreateHoleMkNCseq()", 
			status, status != PRO_TK_NO_ERROR );
            if( status == PRO_TK_NO_ERROR )
            {
                status = ProMenuProcess( (char*)"TkDepBlind", &blind_action );
                TEST_CALL_REPORT( "ProMenuProcess()", 
                    "ProTestCreateHoleMkNCseq()", 
	            status, status != PRO_TK_NO_ERROR );
            }             
            if (blind_action == BLIND_ENTER)
            {
                ProUtilMsgPrint ((char*)"gen", (char*)"TEST %0s", 
                    "Enter drill depth [0.0]:");
                status = ProMessageDoubleRead (NULL, &depth);
                TEST_CALL_REPORT("ProMessageDoubleRead()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
                if (status != PRO_TK_NO_ERROR)
                   depth = 0.0;
                status = ProNcseqElemHolesetDepthSet (*holes, set_nmb, depth);
                TEST_CALL_REPORT("ProNcseqElemHolesetDepthSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
            }
            else
            {
                ProUtilMsgPrint ((char*)"gen", (char*)"TEST %0s", 
                    "Select end surface or datum plane");
                status = ProSelect((char*)"surface,datum", 1,
                    NULL, NULL, NULL, NULL, &start_sels, &num_selected);
                TEST_CALL_REPORT("ProSelect()", "ProTestCreateHoleMkNCseq()", 
                    status, status != PRO_TK_NO_ERROR);
                if (status != PRO_TK_NO_ERROR || num_selected != 1)
                    return ((ProError)0);
                status = ProNcseqElemHolesetEndSet (*holes, 
                    set_nmb, start_sels[0]);
                TEST_CALL_REPORT("ProNcseqElemHolesetEndSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
            }
        }
        else
        {            
            status = ProMfgTypeGet (mfg_model, &type);
            TEST_CALL_REPORT("ProMfgTypeGet()",
                "ProTestCreateHoleMkNCseq()", status,
                (status != PRO_TK_NO_ERROR));
            ProTKPrintf ((char*)"Current type %d\n", type);
            ProTKPrintf ((char*)"ASSM %d, PART %d", PRO_MFGTYPE_MACH_ASSEM, PRO_MFGTYPE_MACH_PART);
            if (type == PRO_MFGTYPE_MACH_ASSEM)
            {
                ProUtilMsgPrint ((char*)"gen", (char*)"TEST %0s", 
                    "Select drill parts");
                status = ProSelect((char*)"part", -1,
                    NULL, NULL, NULL, NULL, &start_sels, &num_selected);
                TEST_CALL_REPORT("ProSelect()", "ProTestCreateHoleMkNCseq()", 
                    status, status != PRO_TK_NO_ERROR);
                if (status != PRO_TK_NO_ERROR || num_selected != 1)
                    return ((ProError)0);
                for (i = 0; i < num_selected; i++)
                {
                    status = ProNcseqElemHolesetDrillpartAdd (*holes, set_nmb,
                        start_sels[i]);
                    TEST_CALL_REPORT("ProNcseqElemHolesetDrillpartAdd()", "ProTestCreateHoleMkNCseq()", 
                        status, status != PRO_TK_NO_ERROR);
                }
            }
        }
        
        if (action == PRO_DRILL_BLIND ||
            action == PRO_DRILL_AUTO)
        {
/*--------------------------------------------------------------------*\
            Set the depth type (can be _BY_TIP or _BY_SHOULDER)
\*--------------------------------------------------------------------*/
            status = ProMenuFileRegister( (char*)"TkDepBySet", (char*)"tkdepbyset.mnu", &menu_id );
            TEST_CALL_REPORT( "ProMenuFileRegister()", 
                "ProTestCreateHoleMkNCseq()", 
                status, status != PRO_TK_NO_ERROR );

            /* Define menu buttons */
            ProMenubuttonActionSet( (char*)"TkDepBySet", (char*)"By Shoulder",
                (ProMenubuttonAction)ProTestDepTypeAction, NULL, 
                PRO_DRILL_BY_SHOULDER);
            ProMenubuttonActionSet( (char*)"TkDepBySet", (char*)"By Tip",
                (ProMenubuttonAction)ProTestDepTypeAction, NULL, 
                PRO_DRILL_BY_TIP);
            ProMenubuttonActionSet( (char*)"TkDepBySet", (char*)"TkDepBySet", 
                (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
            status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDepBySet", &menu_id );
            TEST_CALL_REPORT( "ProMenuCreate()", "ProTestCreateHoleMkNCseq()", 
			status, status != PRO_TK_NO_ERROR );
            if( status == PRO_TK_NO_ERROR )
            {
                status = ProMenuProcess( (char*)"TkDepBySet", &action );
                TEST_CALL_REPORT( "ProMenuProcess()", 
                    "ProTestCreateHoleMkNCseq()", 
	            status, status != PRO_TK_NO_ERROR );
            }
            status = ProNcseqElemHolesetDepthBySet( *holes, set_nmb, (ProDrillDepthByType)action);
            TEST_CALL_REPORT("ProNcseqElemHolesetDepthBySet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
        }
                         
        status = ProMenuFileRegister( (char*)"TkDirect", (char*)"tkdepdirect.mnu", &menu_id );
        TEST_CALL_REPORT( "ProMenuFileRegister()", 
            "ProTestCreateHoleMkNCseq()", 
	    status, status != PRO_TK_NO_ERROR );

        /* Define menu buttons */
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"Natural",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_HS_DIR_NATURAL);
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"Flip",
            (ProMenubuttonAction)ProTestDepTypeAction, NULL, PRO_HS_DIR_FLIP);
        ProMenubuttonActionSet( (char*)"TkDirect", (char*)"TkDirect", 
            (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
        status = ProMenuCreate( PROMENUTYPE_MAIN, (char*)"TkDirect", &menu_id );
        TEST_CALL_REPORT( "ProMenuCreate()", "ProTestCreateHoleMkNCseq()", 
			status, status != PRO_TK_NO_ERROR );
        if( status == PRO_TK_NO_ERROR )
        {
            status = ProMenuProcess( (char*)"TkDirect", &action );
            TEST_CALL_REPORT( "ProMenuProcess()", "ProTestCreateHoleMkNCseq()", 
	        status, status != PRO_TK_NO_ERROR );
        }                     
        status = ProNcseqElemHolesetDirectionSet (*holes, set_nmb, (ProHolesetDirection)action);
        TEST_CALL_REPORT("ProNcseqElemHolesetDirectionSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
        if (drill_action == DRILL_CSINK)
        {
            ProUtilMsgPrint ((char*)"gen", (char*)"TEST %0s", 
                "Enter countersink diameter [QUIT]:");
            status = ProMessageDoubleRead (NULL, &csink);
            TEST_CALL_REPORT("ProMessageDoubleRead()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
            if (status == PRO_TK_NO_ERROR)
            {
                status = ProNcseqElemHolesetCsinkdiamSet (*holes, set_nmb, csink);
                TEST_CALL_REPORT("ProNcseqElemHolesetCsinkdiamSet()",
                             "ProTestCreateHoleMkNCseq()", status,
                             (status != PRO_TK_NO_ERROR));
            }
        }
        return status;
}


/*====================================================================*\
FUNCTION : ProUtilParamFileRead()
PURPOSE  : Read in a file of parameters output an filled elem structure
\*====================================================================*/
ProError ProUtilParamFileRead(
    char *file_name,
    ParamFileType param_type,
    void *p_elem)
{
    ProParamvalue temp_val;
    ProError status;
    char param_name[PARAM_FIELD_WIDTH];
    char param_value[PARAM_FIELD_WIDTH];
    char name[PARAM_FIELD_WIDTH];
    char value[PARAM_FIELD_WIDTH];
    wchar_t wvalue[PARAM_FIELD_WIDTH];
    FILE *fp;
    int ivalue, line_number = 0;
    double dvalue;
    ValueType type;
    int cont = 1;

/*--------------------------------------------------------------------*\
    Open Manufacturing parameters file
\*--------------------------------------------------------------------*/
    if ( (fp = PTApplsUnicodeFopen(file_name,"r") ) == NULL)
        return (PRO_TK_BAD_INPUTS);

/*--------------------------------------------------------------------*\
    Read in parameters line by line
\*--------------------------------------------------------------------*/
    while(cont)
    {
        line_number++;

        if ( (fgets(param_name,  PARAM_FIELD_WIDTH, fp)) == NULL)
        {
            fclose(fp);
            return (PRO_TK_NO_ERROR);
        }
        parse_string(param_name, name);

        fgets(param_value, PARAM_FIELD_WIDTH, fp);
        type = parse_string(param_value, value);

        switch (type)
        {
            case ERROR:
                ProTKFprintf(stderr, (char*)"Error parsing param file: line %d\n",
                                                           line_number);
                fclose(fp);
                return(PRO_TK_BAD_INPUTS);
            case EMPTY:
                break;
            case STRING:
                ProStringToWstring(wvalue, value);
                status = ProParamvalueSet(&temp_val,&wvalue,PRO_PARAM_STRING);
                TEST_CALL_REPORT("ProParamvalueSet()",
                    "ProUtilParamFileRead()", status,
                        (status != PRO_TK_NO_ERROR));
                break;
            case INT:
                ivalue = atoi(param_value);
                status = ProParamvalueSet(&temp_val,&ivalue,PRO_PARAM_INTEGER);
                TEST_CALL_REPORT("ProParamvalueSet()",
                    "ProUtilParamFileRead()", status,
                        (status != PRO_TK_NO_ERROR));
                break;
            case DOUBLE:
                dvalue = (double) atof(param_value);
                status = ProParamvalueSet(&temp_val,&dvalue,PRO_PARAM_DOUBLE);
                TEST_CALL_REPORT("ProParamvalueSet()",
                    "ProUtilParamFileRead()", status,
                        (status != PRO_TK_NO_ERROR));
                break;
            }

        if ((type != ERROR ) && ( type != EMPTY))
        {
/*--------------------------------------------------------------------*\
            Now add the parameter to the correct element type
\*--------------------------------------------------------------------*/
            switch(param_type)
            {
                case MACHINE:
                    /* Add code to create a value object, set its
                       data and add to the element. */
                    break;

                case TOOL:
                    status =
                        ProToolElemParamAdd((ProToolElem)(p_elem),
                                                           &temp_val, name);
                    TEST_CALL_REPORT("ProToolElemParamAdd()",
                        "ProUtilParamFileRead()", status,
                        (status != PRO_TK_NO_ERROR));
                    break;
            }
        }
    }

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProTestToolPathDisplay()
PURPOSE  : query the user for the Nc sequence and display its tool path
\*====================================================================*/
ProError ProTestNcseqToolPathDisplay()
{
    ProMfg mfg_model;
    ProAsmcomppath comp_path;
    ProSolid mfg_solid;
    ProNcseq* p_sel_ncseq;
    ProError status;

    status = ProTestGetModels( &mfg_model, &mfg_solid, &comp_path);

    p_sel_ncseq = ProUtilNcseqChoose( &mfg_solid);

    if (p_sel_ncseq != NULL)
     {
       status = ProNcseqToolpathDisplay(p_sel_ncseq);
       TEST_CALL_REPORT("ProNcseqToolpathDisplay()",
                        "ProTestToolPathDisplay()", status,
                        (status != PRO_TK_NO_ERROR));
     }
    else
       ProUtilMsgPrint((char*)"gen", (char*)"TEST %0s",(char*)"No NCsequences available");

    return ((ProError)0);
}

/*====================================================================*\
FUNCTION : parse_string()
PURPOSE  : return type and removes leading and trailing whitespace
\*====================================================================*/
static ValueType parse_string(
    const char *s,
    char *out)
{
    int is_number = 0;
    ValueType type = ERROR;

    while( *s == ' ') s++;

    if ( *s == '-' && !isalnum(*(s+1)))
    {
        out = '\0';
        return (EMPTY);
    }

    if (isdigit(*s))
        is_number = 1;

    if (isalpha(*s))
        type = STRING;

    for (; isprint(*s) && *s != ' ' && *s != '\n' ; s++,out++)
    {
        if (is_number && *s == '.')
            type = DOUBLE;
        *out = *s;
    }
    *out = '\0';

    if (type == DOUBLE)
        return (DOUBLE);

    if (is_number)
        return (INT);
    else
                return type;
}

ProError ProUtilSectionRetr(ProSection *section);
/*====================================================================*\
FUNCTION : ProTestToolPathDisplay()
PURPOSE  : query the user for the Nc sequence and display its tool path
\*====================================================================*/
ProError ProUtilStockBoundSketchAdd (
    ProElement *stk_bnd_sk_elem )
{
    ProError status;
    ProSection sec;
    ProValueData vd;
    ProValue vl;

    status = ProValueAlloc(&vl);
    if (status != PRO_TK_NO_ERROR)
	return status;   

    status = ProUtilSectionRetr(&sec);
    if (status != PRO_TK_NO_ERROR)
	return status;

	status = ProElementSpecialvalueSet(*stk_bnd_sk_elem, (ProAppData) sec);
	TEST_CALL_REPORT("ProElementSpecialvalueSet()",
                        "ProUtilStockBoundSketchAdd()", status,
                        (status != PRO_TK_NO_ERROR));

    return status;
}