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

#include <ProToolkit.h>
#include <ProMfg.h>
#include <ProSolid.h>
#include <ProSelection.h>
#include <ProAsmcomppath.h>
#include <ProElement.h>
#include <ProElemId.h>
#include <ProValue.h>
#include <ProFeature.h>
#include <ProUtil.h>
#include <ProTool.h>
#include <ProMfgOptions.h>
#include <ProAsmcomp.h>
#include <ProCrvcollection.h>
#include <ProFeatType.h>
#include <ProWcell.h>
#include <ProMdlUnits.h>
#include <ProSrfcollection.h>

#include <TestError.h>
#include <UtilString.h>
#include <UtilTree.h>
#include <UtilCollect.h>
#include <UtilVisit.h>
#include <TestConsts.h>
#include <PTApplsUnicodeUtils.h>
#include <ProMessage.h>
#include <ProModelitem.h>
#include <UtilMessage.h>
#include <UgMfg.h>

/***********************************************************************/
/*  Sequence type                             Function                 */
/*---------------------------------------------------------------------*/
/*  PRO_NCSEQ_FACE_MILL                       UserFacingCreate         */
/*  PRO_NCSEQ_TRAJ_MILL_STEP                  UserTrajectoryCreate     */
/*  PRO_NCSEQ_FF_TRAJ_MILL                    UserCurveTrajCreate      */
/*  PRO_NCSEQ_ROUGHVOL_MILL                   UserRoughingCreate       */
/*  PRO_NCSEQ_REROUGH_MILL                    UserReRoughingCreate     */
/*  PRO_NCSEQ_CVNC_FINISH_MILL                UserFinishingCreate      */
/*  PRO_NCSEQ_PROF_SURF_MILL                  UserProfilingCreate      */
/*  PRO_NCSEQ_MANUAL_CYCLE_MILL               UserManualCycleCreate    */
/*  PRO_NCSEQ_HOLEMAKING (PRO_HOLE_MK_CSINK)  UserCSinkgCreate         */
/*  PRO_NCSEQ_HOLEMAKING (PRO_HOLE_MK_DRILL)  UserDrillingCreate       */
/***********************************************************************/

extern ProLine msg_fil17;
#define MSG_FIL ProStringToWstring(msg_fil17,"msg_ugmfg.txt")


typedef struct 
{ 
    ProMfg       model;
    ProSelection operation;
    ProBoolean   oper_found;
    ProSelection retract_plane;
    ProBoolean   retract_found;
    ProSelection face_mill_window;
    ProBoolean   face_mill_wind_found;
    ProSelection pocket_mill_window;
    ProBoolean   pocket_mill_wind_found;
    ProSelection traj_curve;
    ProBoolean   traj_curve_found;
    ProSelection prof_mill_surf;
    ProBoolean   prof_mill_surf_found;
    ProSelection csys;
    ProBoolean   csys_found;

} NcseqEnts ;



/*====================================================================*\
Function : UserPlaneGeomIdGet
Purpose  : Get the id of the datum plane feature's geometry
\*====================================================================*/
ProError UserGeomItemGet  ( 
/*--------------------------------------------------------------------*/
ProGeomitem	*geomitem,
ProError	err,
ProAppData	app_data 

)
/*--------------------------------------------------------------------*/
{
 *(ProGeomitem*)app_data = *geomitem;

 return ( PRO_TK_E_FOUND );
}

/*====================================================================*\
Function : UserNcseqEntitiesCollect
Purpose  : Collect sequence references and use them to create a sequence
\*====================================================================*/
ProError UserNcseqEntitiesCollect (
/*--------------------------------------------------------------------*/
ProFeature	*feature,
ProError	status,
ProAppData	entities 

)
/*--------------------------------------------------------------------*/
{
 ProError	err;
 ProFeattype	feat_type;
 ProWcellType	wcell_type;
 NcseqEnts	*seq_ents = (NcseqEnts*)entities;
 ProSelection	selection;
 ProGeomitem    geom_item;
 ProName	w_name;
 ProCharName	name;
 int		id;

 err = ProFeatureTypeGet( feature, &feat_type );
 ERROR_CHECK( "UserNcseqEntitiesCollect", "ProFeatureTypeGet()",err );

 if ( !seq_ents->oper_found && feat_type == PRO_FEAT_OPERATION )
 {
   err = ProSelectionAlloc( NULL, feature, &selection );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

   ProSelectionCopy( selection, &seq_ents->operation );
   seq_ents->oper_found = PRO_B_TRUE;
 }
 else if ( !seq_ents->prof_mill_surf_found && 
           feat_type == PRO_FEAT_DATUM_SURF )
 {
   err = ProModelitemNameGet( feature, w_name );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProModelitemNameGet()", err );

   ProWstringToString( name, w_name );

   if ( !strcmp( name,"PROF_MILL_SURF" ) )
   {
     err = ProFeatureGeomitemVisit( feature, PRO_QUILT, UserGeomItemGet,
                                    NULL, (ProAppData)&geom_item );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProFeatureGeomitemVisit()",
                   err );

     err = ProSelectionAlloc( NULL, (ProModelitem*)&geom_item, &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->prof_mill_surf );
     seq_ents->prof_mill_surf_found = PRO_B_TRUE;
   }
 }
 else if ( feat_type == PRO_FEAT_CURVE )
 {
   err = ProModelitemNameGet( feature, w_name );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProModelitemNameGet()", err );

   ProWstringToString( name, w_name );

   if ( !seq_ents->face_mill_wind_found && 
        !strcmp( name,"FACE_MILL_WINDOW" ) )
   {
     err = ProSelectionAlloc( NULL, feature, &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->face_mill_window );
     seq_ents->face_mill_wind_found = PRO_B_TRUE;
   }
   else if ( !seq_ents->pocket_mill_wind_found && 
             !strcmp( name,"ROUGH_MILL_WINDOW" ) )
   {
     err = ProSelectionAlloc( NULL, feature, &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->pocket_mill_window );
     seq_ents->pocket_mill_wind_found = PRO_B_TRUE;
   }
   else if ( !seq_ents->traj_curve_found && 
             !strcmp( name,"TRAJ_CURVE" ) )
   {
     err = ProFeatureGeomitemVisit( feature, PRO_CURVE, UserGeomItemGet,
                                    NULL, (ProAppData)&geom_item );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProFeatureGeomitemVisit()",
                   err );

     err = ProSelectionAlloc( NULL, (ProModelitem*)&geom_item, 
                              &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->traj_curve );
     seq_ents->traj_curve_found = PRO_B_TRUE;
   }
 }
 else if ( !seq_ents->retract_found && feat_type == PRO_FEAT_DATUM )
 {
   err = ProModelitemNameGet( feature, w_name );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProModelitemNameGet()", err );

   ProWstringToString( name, w_name );

   if ( !strcmp( name,"RETRACT_PLANE" ) )
   {
     err = ProFeatureGeomitemVisit( feature, PRO_SURFACE, UserGeomItemGet,
                                    NULL, (ProAppData)&geom_item );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProFeatureGeomitemVisit()",
                   err );

     err = ProSelectionAlloc( NULL, (ProModelitem*)&geom_item, 
                              &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->retract_plane );
     seq_ents->retract_found = PRO_B_TRUE;
   }
 }
 else if ( !seq_ents->csys_found && feat_type == PRO_FEAT_CSYS )
 {
   err =  ProModelitemNameGet( feature, w_name );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProModelitemNameGet()", err );

   ProWstringToString( name, w_name );

   if ( !strcmp( name,"MACH_CSYS" ) )
   {
     err = ProFeatureGeomitemVisit( feature, PRO_CSYS, UserGeomItemGet, 
                                    NULL, &geom_item );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProFeatureGeomitemVisit()",
                  err );

     err = ProSelectionAlloc( NULL, (ProModelitem*)&geom_item, &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     ProSelectionCopy( selection, &seq_ents->csys );

     err = ProSelectionHighlight( seq_ents->csys, PRO_COLOR_WARNING );
     ERROR_CHECK( "UserNcseqEntitiesCollect","ProSelectionHighlight()", err );
     seq_ents->csys_found = PRO_B_TRUE;
   }
 }

 if ( seq_ents->oper_found       && 
      seq_ents->retract_found    && 
      seq_ents->face_mill_wind_found  && 
      seq_ents->pocket_mill_wind_found  && 
      seq_ents->prof_mill_surf_found  && 
      seq_ents->traj_curve_found && 
      seq_ents->csys_found )
 {
   return PRO_TK_STOP_VISIT;
 }

 return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION : UserCollectAxesToDrill
PURPOSE  : Finds all axes in part
\*====================================================================*/
ProError UserCollectAxesToDrill( 
/*--------------------------------------------------------------------*/
ProAssembly	assembly,
ProSelection	**p_sel_arr

)
/*--------------------------------------------------------------------*/
{
 ProError	err = PRO_TK_NO_ERROR;
 ProAsmcomp	*asmcomps = NULL;
 ProAsmcomppath	comp_path;
 ProIdTable	memb_id_tab;
 ProAxis	*axes = NULL;
 ProMdlfileType	mdltype;
 ProSelection	selection;
 ProMdl		model;
 ProFamilyMdlName	w_name;
 char	name[PRO_FAMILY_MDLNAME_SIZE];
 ProGeomitem	item;
 int		ii, num_comp = 0;
 int		jj, num_axes = 0;
 ProBool	found = PRO_B_FALSE;

 err = ProUtilCollectAsmcomp( assembly, &asmcomps );
 ERROR_CHECK( "UserCollectAxesToDrill", "ProUtilCollectAsmcomp()", err );

 ProArraySizeGet( (ProArray)asmcomps, &num_comp );

 for ( ii = 0; ii < num_comp; ii++ )
 {
   err = ProAsmcompMdlMdlnameGet( &asmcomps[ii], &mdltype, w_name );
   ERROR_CHECK( "UserCollectAxesToDrill", "ProAsmcompMdlMdlnameGet()", err );

   ProWstringToString( name, w_name );

   if ( !strcmp( name,"COVER-PLATE" ) )
   {
     err = ProAsmcompMdlGet( &asmcomps[ii], &model );
     ERROR_CHECK( "UserCollectAxesToDrill", "ProAsmcompMdlGet()", err );
    
     memb_id_tab[0] = asmcomps[ii].id;
     memb_id_tab[1] = -1;

     err = ProAsmcomppathInit( assembly, memb_id_tab, 1, &comp_path );
     ERROR_CHECK( "UserCollectAxesToDrill", "ProAsmcomppathInit()", err );

     found = PRO_B_TRUE;
     break;
   }
 }

 if ( !found )
   return ( PRO_TK_E_NOT_FOUND );

 err = ProUtilCollectSolidAxis( (ProSolid)model, &axes );
 ERROR_CHECK( "UserCollectAxesToDrill", "ProUtilCollectSolidAxis()", err );

 err = ProArraySizeGet( axes, &num_axes );
 ERROR_CHECK( "UserCollectAxesToDrill", "ProArraySizeGet()", err );

 err = ProArrayAlloc( 0, sizeof(ProSelection), 1, (ProArray*)p_sel_arr );
 ERROR_CHECK( "UserCollectAxesToDrill", "ProArrayAlloc()", err );

 for ( jj = 0; jj < num_axes; jj++ )
 {
   err = ProAxisToGeomitem( (ProSolid)model, axes[jj], &item );
   ERROR_CHECK( "UserCollectAxesToDrill", "ProAxisToGeomitem()", err );

   err = ProModelitemNameGet( (ProModelitem*)&item, w_name );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProModelitemNameGet()", err );

   ProWstringToString( name, w_name );

   if ( !strcmp( name,"A_1"  )  ||
        !strcmp( name,"A_9"  )  ||
        !strcmp( name,"A_10" )  ||
        !strcmp( name,"A_11" ) )
   {
     err = ProSelectionAlloc( &comp_path, (ProModelitem*)&item, &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

     err = ProArrayObjectAdd( (ProArray *)p_sel_arr, PRO_VALUE_UNUSED, 1, 
                              &selection );
     ERROR_CHECK( "UserNcseqEntitiesCollect", "ProArrayObjectAdd()", err );
   }
 }

 ProArrayFree( (ProArray*)&asmcomps );
 ProArrayFree( (ProArray*)&axes );

 return ( err );
}

/*====================================================================*\
FUNCTION : UserOperWorkcellGet
PURPOSE  : Finds workcell of operation
\*====================================================================*/
ProError UserOperWorkcellGet( 
/*--------------------------------------------------------------------*/
ProSelection	operation,
ProSelection	*p_workcell

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		elem_tree;
 ProElement		element;
 ProFeature		oper_feat;
 ProReference		wcell_ref;
 ProElempath		path;
 ProElempathItem	wcell_ref_path_item[] = 
 {
   { PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_MFG_WCELL_REF }
 };

 err = ProSelectionModelitemGet( operation, &oper_feat );
 ERROR_CHECK( "UserOperWorkcellGet", "ProSelectionModelitemGet", err );

 err = ProFeatureElemtreeExtract( &oper_feat, NULL, 
                                  PRO_FEAT_EXTRACT_NO_OPTS, 
                                  &elem_tree );
 ERROR_CHECK( "UserOperWorkcellGet", "ProSelectionModelitemGet", err );

 ProElempathAlloc( &path );
 ProElempathDataSet( path, wcell_ref_path_item, 1 );

 err = ProElemtreeElementGet( elem_tree, path, &element );
 ERROR_CHECK( "UserOperWorkcellGet", "ProElemtreeElementGet", err );

 ProElempathFree( &path );
   
 err = ProElementReferenceGet( element, NULL, &wcell_ref );
 ERROR_CHECK( "UserOperWorkcellGet", "ProElementReferenceGet", err );

 err = ProReferenceToSelection( wcell_ref, p_workcell );
 ERROR_CHECK( "UserOperWorkcellGet", "ProReferenceToSelection", err );

 err = ProElementFree( &elem_tree );
 ERROR_CHECK( "UserOperWorkcellGet", "ProElementFree", err );

 return ( err );
}

/*====================================================================*\
Function : UserMfgModelFeatureCreate
Purpose  : Create a feature in mfg model from elem tree
\*====================================================================*/
ProError UserMfgModelFeatureCreate (
/*--------------------------------------------------------------------*/
ProMfg		mfg_model,
ProElement	elem_tree,
ProFeature	*p_feature

)
/*--------------------------------------------------------------------*/
{
 ProError		  err = PRO_TK_NO_ERROR;
 ProErrorlist		  errors;
 ProSolid		  mfg_solid;
 ProModelitem		  modelitem;
 ProSelection		  selection;
 ProFeatureCreateOptions  fd_opts[] = { PRO_FEAT_CR_DEFINE_MISS_ELEMS };

 err = ProMfgSolidGet( mfg_model, &mfg_solid );
 ERROR_CHECK( "UserMfgModelFeatureCreate", "ProMfgSolidGet()", err );

 err = ProMdlToModelitem( mfg_solid, &modelitem );
 ERROR_CHECK( "UserMfgModelFeatureCreate", "ProMdlToModelitem()", err );

 err = ProSelectionAlloc( NULL, &modelitem, &selection );
 ERROR_CHECK( "UserMfgModelFeatureCreate", "ProSelectionAlloc()", err );

 err = ProFeatureCreate( selection, elem_tree, fd_opts, 1,
                         p_feature, &errors );

 if ( err != PRO_TK_NO_ERROR )
   ProTKFprintf( stderr, "Error in element %d\n", 
                 errors.error_list[0].err_item_id );

 return ( (int)err );
}

/*====================================================================*\
FUNCTION : UserMachSurfByWindowSet
PURPOSE  : Set machining surfaces by mill window compound element 
\*====================================================================*/
ProError UserMachSurfByWindowSet( 
/*--------------------------------------------------------------------*/
ProSelection	mill_window,
ProElement	mach_surf_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 ProSelection		selection;
 ProReference		reference;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MACH_SURF_OPT,     PRO_VALUE_TYPE_INT       },
   { PRO_E_MFG_MILL_WIND_SRF, PRO_VALUE_TYPE_SELECTION }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMachSurfByWindowSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MACH_SURF_OPT:
		err = ProElementIntegerSet ( element, PRO_MACH_SURF_OPT_MILL_WIND );
        ERROR_CHECK( "UserMachSurfByWindowSet"," ProElementIntegerSet",err );
        break;

     case PRO_E_MFG_MILL_WIND_SRF:
        selection = mill_window;
		err = ProSelectionToReference(selection , &reference );
		ERROR_CHECK( "UserMachSurfByWindowSet()", "ProSelectionToReference", 
                  err );

		err = ProElementReferenceSet( element, reference );
		ERROR_CHECK( "UserMachSurfByWindowSet()", "ProElementReferenceSet", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserMachSurfByWindowSet","UserMachSurfByWindowSet()", 
                     err );
        break;
   }

   err = ProElemtreeElementAdd( mach_surf_elem, NULL, element );
   ERROR_CHECK( "UserMachSurfByWindowSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserCurveCollectionSet
PURPOSE  : Set curve collection by curve
\*====================================================================*/
ProError UserCurveCollectionSet( 
/*--------------------------------------------------------------------*/
ProSelection	curve_feat,
ProElement	coll_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProReference		reference;
 ProCollection		collection;
 ProCrvcollinstr	instr;

 err = ProCrvcollectionAlloc( &collection );
 ERROR_CHECK( "UserCurveCollectionSet","ProCrvcollectionAlloc", err );

 err = ProCrvcollinstrAlloc( PRO_CURVCOLL_CURVE_INSTR, &instr );
 ERROR_CHECK( "UserCurveCollectionSet","ProSrfcollinstrAlloc", err );

 err = ProCrvcollinstrAttributeSet( instr, PRO_CURVCOLL_NO_ATTR );
 ERROR_CHECK( "UserCurveCollectionSet", "ProCrvcollinstrAttributeSet", err );

 err = ProSelectionToReference( curve_feat, &reference );
 ERROR_CHECK( "UserCurveCollectionSet","ProSelectionToReference", err );

 err = ProCrvcollinstrReferenceAdd( instr, reference );
 ERROR_CHECK( "UserCurveCollectionSet", "ProCrvcollinstrReferenceAdd", err );

 err = ProCrvcollectionInstructionAdd( collection, instr );
 ERROR_CHECK( "UserCurveCollectionSet", "ProCrvcollectionInstructionAdd", 
              err );

 err = ProElementCollectionSet( coll_elem, collection );
 ERROR_CHECK( "UserCurveCollectionSet", "ProElementCollectionSet", err );

 return ( err );
}

/*====================================================================*\
FUNCTION : UserSurfCollectionByMillSurfSet
PURPOSE  : Set surfaces collection by mill surface
\*====================================================================*/
ProError UserSurfCollectionByMillSurfSet( 
/*--------------------------------------------------------------------*/
ProSelection	mill_surface,
ProElement	coll_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 ProReference		reference;
 ProCollection		collection;
 ProSrfcollinstr	instr;
 ProSrfcollref		isntr_ref;

 err = ProSrfcollectionAlloc( &collection );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSrfcollectionAlloc", 
              err );

 err = ProSrfcollinstrAlloc( PRO_SURFCOLL_QUILT_SRFS, PRO_B_TRUE, &instr );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSrfcollinstrAlloc", 
              err );

 err = ProSrfcollinstrIncludeSet( instr, 1 );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSrfcollinstrIncludeSet", 
              err );

 err = ProSelectionToReference( mill_surface, &reference );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSelectionToReference", 
              err );

 err = ProSrfcollrefAlloc( PRO_SURFCOLL_REF_GENERIC, reference, &isntr_ref );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSrfcollrefAlloc", err );

 err = ProSrfcollinstrReferenceAdd( instr, isntr_ref );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet","ProSrfcollinstrReferenceAdd",
              err );

 err = ProSrfcollectionInstructionAdd( collection, instr );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet",
              "ProSrfcollectionInstructionAdd", err );

 err = ProElementCollectionSet( coll_elem, collection );
 ERROR_CHECK( "UserSurfCollectionByMillSurfSet", "ProElementCollectionSet", 
              err );

 return ( err );
}

/*====================================================================*\
FUNCTION : UserMfgOffsetSet
PURPOSE  : Set mfg offset element
\*====================================================================*/
ProError UserMfgOffsetSet( 
/*--------------------------------------------------------------------*/
ProBool			apply_offset,
ProMaterialRmvSide	material_side,
ProBool			flip_crv_dir,
ProElement		offset_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MFG_OFFSET_CUT,  PRO_VALUE_TYPE_INT },
   { PRO_E_MFG_MAT_TO_RMV,  PRO_VALUE_TYPE_INT },
   { PRO_E_MFG_DRV_SRF_DIR, PRO_VALUE_TYPE_INT }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMfgOffsetSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MFG_OFFSET_CUT:
		err = ProElementIntegerSet ( element, (int)apply_offset );
        ERROR_CHECK( "UserMfgOffsetSet","ProElementIntegerSet()", err );
        break;

     case PRO_E_MFG_MAT_TO_RMV:
		err = ProElementIntegerSet ( element, (int)material_side );
        ERROR_CHECK( "UserMfgOffsetSet","ProElementIntegerSet()", err );
          break;

     case PRO_E_MFG_DRV_SRF_DIR:
		err = ProElementIntegerSet ( element, (int)flip_crv_dir );
        ERROR_CHECK( "UserMfgOffsetSet","ProElementIntegerSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        break;
   }

   err = ProElemtreeElementAdd( offset_elem, NULL, element );
   ERROR_CHECK( "UserMfgOffsetSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserTrajCurveSet
PURPOSE  : Set trajectory curve collection compound element
\*====================================================================*/
ProError UserTrajCurveSet( 
/*--------------------------------------------------------------------*/
ProSelection	curve_feat,
ProElement	traj_curve_elem

)
/*--------------------------------------------------------------------*/
{
 ProError	err = PRO_TK_NO_ERROR;
 ProElement	element;

 err = ProElementAlloc( PRO_E_STD_CURVE_COLLECTION_APPL, &element );
 ERROR_CHECK( "UserTrajCurveByCurveFeatSet","ProElementAlloc()", err );

 err = UserCurveCollectionSet( curve_feat, element );
 ERROR_CHECK( "UserTrajCurveByCurveFeatSet", "UserCurveCollectionSet()", 
              err );

 err = ProElemtreeElementAdd( traj_curve_elem, NULL, element );
 ERROR_CHECK( "UserTrajCurveByCurveFeatSet", "ProElemtreeElementAdd", err );

 return ( err );
}

/*====================================================================*\
FUNCTION : UserMachSurfCollectionByMillSurfSet
PURPOSE  : Set surfaces collection compound element
\*====================================================================*/
ProError UserMachSurfCollectionByMillSurfSet( 
/*--------------------------------------------------------------------*/
ProSelection	mill_surface,
ProElement	mach_surf_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MACH_SURF_REF_TYPE,       PRO_VALUE_TYPE_INT       },
   { PRO_E_STD_SURF_COLLECTION_APPL, SURF_COLLECTION }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMachSurfCollectionByMillSurfSet","ProElementAlloc()", 
                err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MACH_SURF_REF_TYPE:
		err = ProElementIntegerSet ( element, PRO_SURF_REF_TYPE_MILL_MVOLSRF );
        ERROR_CHECK( "UserMachSurfCollectionByMillSurfSet",
                     "ProElementIntegerSet()", err );
        break;

     case PRO_E_STD_SURF_COLLECTION_APPL:
        err = UserSurfCollectionByMillSurfSet( mill_surface, element );
        ERROR_CHECK( "UserMachSurfCollectionByMillSurfSet",
                     "UserSurfCollectionByMillSurfSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserMachSurfCollectionByMillSurfSet",
                     "UserMachSurfCollectionByMillSurfSet()", err );
        break;
   }

   err = ProElemtreeElementAdd( mach_surf_elem, NULL, element );
   ERROR_CHECK( "UserMachSurfCollectionByMillSurfSet",
                "ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserMachSurfByMillSurfSet
PURPOSE  : Set machining surfaces by mill surface
\*====================================================================*/
ProError UserMachSurfByMillSurfSet( 
/*--------------------------------------------------------------------*/
ProSelection	mill_surf,
ProElement	mach_surf_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MACH_SURF_OPT,  PRO_VALUE_TYPE_INT },
   { PRO_E_MACH_SURF_COMP, COMPOUND           }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMachSurfByWindowSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MACH_SURF_OPT:
		err = ProElementIntegerSet ( element, PRO_MACH_SURF_OPT_SURFACES );
        ERROR_CHECK( "UserMachSurfByWindowSet","ProElementIntegerSet()", err );
        break;

     case PRO_E_MACH_SURF_COMP:
        err = UserMachSurfCollectionByMillSurfSet( mill_surf, element );
        ERROR_CHECK( "UserMachSurfByWindowSet()", "UserMachSurfCompSet", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserMachSurfByWindowSet","UserMachSurfByWindowSet()", 
                     err );
        break;
   }

   err = ProElemtreeElementAdd( mach_surf_elem, NULL, element );
   ERROR_CHECK( "UserMachSurfByWindowSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserMillWindowCompoundSet
PURPOSE  : Set machining surfaces by mill window compound element 
\*====================================================================*/
ProError UserMillWindowCompoundSet( 
/*--------------------------------------------------------------------*/
ProSelection	mill_win,
ProElement	mill_win_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 ProSelection		selection;
 ProReference		reference;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MFG_MILL_WIND, PRO_VALUE_TYPE_SELECTION }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMillWindowCompoundSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MFG_MILL_WIND:
        selection = mill_win;
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserMillWindowCompoundSet","UserMillWindowCompoundSet()", 
                     err );
        break;
   }

   if ( elem_table[ii].val_type == PRO_VALUE_TYPE_SELECTION )
   {
     err = ProSelectionToReference( selection, &reference );
     ERROR_CHECK( "UserMillWindowCompoundSet()", "ProSelectionToReference", 
                  err );

     err = ProElementReferenceSet( element, reference );
     ERROR_CHECK( "UserMillWindowCompoundSet()", "ProElementReferenceSet",
                  err );
   }

   err = ProElemtreeElementAdd( mill_win_elem, NULL, element );
   ERROR_CHECK( "UserMillWindowCompoundSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
Function : UserFacingCreate
Purpose  : Create a facing sequence feature using element tree
\*====================================================================*/
ProError UserFacingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   mill_window,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 int			n_str_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MACH_SURFS,  COMPOUND }
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0    },   /* required for facing    */
   { "STEP_DEPTH",          10.0     },   /* required for facing    */
   { "STEP_OVER",           50.0     },   /* required for facing    */
   { "CLEAR_DIST",          1.0      },   /* required for facing    */
   { "SPINDLE_SPEED",       15000.0  },   /* required for facing    */
   { "RETRACT_FEED",        500.0    }    /* example (not required) */
 };

 static MfgPrmStrValue	str_params[] =  /* examples (not required) */
 {
   { "SCAN_TYPE",           L"TYPE_1" },  /* Predefined SCAN_TYPE value */
   { "NCL_FILE",            L"Facing" }   /* Cl file name               */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
 n_str_params = sizeof( str_params ) / sizeof( MfgPrmStrValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserFacingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL, 
                                       PRO_NCSEQ_FACE_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       str_params,
                                       n_str_params,
                                       seq_elem_tree );

 ERROR_CHECK( "UserFacingCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*********************************************/
 /* Add elements specific for facing sequence */
 /*********************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserFacingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MACH_SURFS:
        err = UserMachSurfByWindowSet( mill_window, element );
        ERROR_CHECK( "UserFacingCreate()", "UserMachSurfByWindowSet", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserFacingCreate", "UserFacingCreate()", err );
        break;
   }
	
   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserFacingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserFacingCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserFacingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserTrajectoryCreate
Purpose  : Create a trajectory milling feature using element tree
\*====================================================================*/
ProError UserTrajectoryCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   curve,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_TOOL_MTN_ARR, ARRAY },
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0    },  /* required for trajectory */
   { "CLEAR_DIST",          1.0      },  /* required for trajectory */
   { "SPINDLE_SPEED",       15000.0  }   /* required for trajectory */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserTrajectoryCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_TRAJ_MILL_STEP, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserTrajectoryCreate()", "UserNcSeqTreeCommonElementsAdd", 
              err );

 /*************************************************/
 /* Add elements specific for trajectory sequence */
 /*************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserTrajectoryCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_TOOL_MTN_ARR:
        err = UserTrajToolMtnArrSet( curve, element );
        ERROR_CHECK( "UserTrajectoryCreate","UserTrajToolMtnArrSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserTrajectoryCreate","UserTrajectoryCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserTrajectoryCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserTrajectoryCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserTrajectoryCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserCurveTrajCreate
Purpose  : Create a roughing milling feature using element tree
\*====================================================================*/
ProError UserCurveTrajCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   curve_feat,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 int			n_str_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MFG_TRAJ_CRV, COMPOUND },
   { PRO_E_MFG_OFFSET,   COMPOUND }

 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0   },   /* required for 2-axis trajectory */
   { "CLEAR_DIST",          1.0     },   /* required for 2-axis trajectory */
   { "SPINDLE_SPEED",       15000.0 },   /* required for 2-axis trajectory */
   { "LEAD_IN_RADIUS",      60.0    },   
   { "LEAD_OUT_RADIUS",     60.0    },   
 };
 static MfgPrmStrValue	str_params[] =
 {
   { "LEAD_IN",      L"YES" },
   { "LEAD_OUT",     L"YES" }
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
 n_str_params = sizeof( str_params ) / sizeof( MfgPrmStrValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserCurveTrajCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_FF_TRAJ_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       str_params,
                                       n_str_params,
                                       seq_elem_tree );

 ERROR_CHECK( "UserCurveTrajCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*************************************************/
 /* Add elements specific for curve trajectory    */
 /*************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserCurveTrajCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MFG_TRAJ_CRV:
        err = UserTrajCurveSet( curve_feat, element );
        ERROR_CHECK( "UserCurveTrajCreate()", "UserTrajCurveSet", err );
        break;

     case PRO_E_MFG_OFFSET:
        err = UserMfgOffsetSet( PRO_B_TRUE, PRO_MAT_RMV_LEFT, PRO_B_TRUE,
                                element );
        ERROR_CHECK( "UserCurveTrajCreate", "UserMfgOffsetSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserCurveTrajCreate","UserCurveTrajCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserCurveTrajCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserCurveTrajCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserCurveTrajCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserFinishingCreate
Purpose  : Create a finishing milling feature using element tree
\*====================================================================*/
ProError UserFinishingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   mill_window,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MFG_CMP_MILL_WIND, COMPOUND },
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0   },   /* required for finishing */
   { "STEP_OVER",           5.0     },   /* required for finishing */
   { "CLEAR_DIST",          1.0     },   /* required for finishing */
   { "SPINDLE_SPEED",       15000.0 }    /* required for finishing */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserFinishingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_CVNC_FINISH_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserFinishingCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*************************************************/
 /* Add elements specific for finishing sequence  */
 /*************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserFinishingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MFG_CMP_MILL_WIND:
        err = UserMillWindowCompoundSet( mill_window, element );
        ERROR_CHECK( "UserFinishingCreate","UserMillWindowCompoundSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserFinishingCreate","UserFinishingCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserFinishingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserFinishingCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserFinishingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserRoughingCreate
Purpose  : Create a roughing milling feature using element tree
\*====================================================================*/
ProError UserRoughingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   mill_window,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name,
ProFeature	   *p_seq_feature

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MFG_CMP_MILL_WIND, COMPOUND },
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0   },   /* required for roughing */
   { "STEP_OVER",           25.0    },   /* required for roughing */
   { "MAX_STEP_DEPTH",      5.0     },   /* required for roughing */
   { "CLEAR_DIST",          1.0     },   /* required for roughing */
   { "SPINDLE_SPEED",       15000.0 }    /* required for roughing */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserRoughingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_ROUGHVOL_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserRoughingCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*************************************************/
 /* Add elements specific for roughing sequence   */
 /*************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserRoughingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MFG_CMP_MILL_WIND:
        err = UserMillWindowCompoundSet( mill_window, element );
        ERROR_CHECK( "UserRoughingCreate","UserMillWindowCompoundSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserRoughingCreate","UserRoughingCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserRoughingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserRoughingCreate", "UserMfgModelFeatureCreate()", err );

 if ( p_seq_feature != NULL )
   *p_seq_feature = seq_feature;

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserRoughingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserReRoughingCreate
Purpose  : Create a re-roughing milling feature using element tree
\*====================================================================*/
ProError UserReRoughingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   seq_sel,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 ProSelection		selection;
 ProReference		reference;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MFG_PREV_SEQ,  PRO_VALUE_TYPE_SELECTION }
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            150.0   },  /* required for re-roughing */
   { "STEP_OVER",           9.0     },  /* required for re-roughing */
   { "MAX_STEP_DEPTH",      5.0     },  /* required for re-roughing */
   { "CLEAR_DIST",          1.0     },  /* required for re-roughing */
   { "SPINDLE_SPEED",       15000.0 }   /* required for re-roughing */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserRoughingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_REROUGH_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserReRoughingCreate()", "UserNcSeqTreeCommonElementsAdd", 
              err );

 /**************************************************/
 /* Add elements specific for re-roughing sequence */
 /**************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserReRoughingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MFG_PREV_SEQ:
        selection = seq_sel;
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserReRoughingCreate","UserReRoughingCreate()", err );
        break;
   }

   if ( seq_elem_table[ii].val_type == PRO_VALUE_TYPE_SELECTION )
   {
     err = ProSelectionToReference( selection, &reference );
     ERROR_CHECK( "UserReRoughingCreate()", "ProSelectionToReference", err );

     err = ProElementReferenceSet( element, reference );
     ERROR_CHECK( "UserReRoughingCreate()", "ProElementReferenceSet", err );
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserReRoughingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserReRoughingCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserReRoughingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserProfilingCreate
Purpose  : Create a profile milling feature using element tree
\*====================================================================*/
ProError UserProfilingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   mill_surf,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name,
ProFeature	   *p_seq_feature

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_MACH_SURFS, COMPOUND },
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0   },   /* required for profile milling */
   { "STEP_DEPTH",          25.0    },   /* required for profile milling */
   { "CLEAR_DIST",          1.0     },   /* required for profile milling */
   { "SPINDLE_SPEED",       15000.0 }    /* required for profile milling */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserProfilingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_PROF_SURF_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserProfilingCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*************************************************/
 /* Add elements specific for profiling sequence  */
 /*************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserProfilingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_MACH_SURFS:
        err = UserMachSurfByMillSurfSet( mill_surf, element );
        ERROR_CHECK( "UserProfilingCreate()", 
                     "UserMachSurfByMillSurfSet", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserProfilingCreate","UserProfilingCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserProfilingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserProfilingCreate", "UserMfgModelFeatureCreate()", err );

 if ( p_seq_feature != NULL )
   *p_seq_feature = seq_feature;

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserProfilingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserCSinkgCreate
Purpose  : Create a countersink holemaking feature using element tree
\*====================================================================*/
ProError UserCSinkgCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
double             csink_diam,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProValueData           value_data;
 ProValue               value;
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_HOLEMAKING_TYPE,            PRO_VALUE_TYPE_INT },
   { PRO_E_MFG_HOLEMAKING_CYCLE_TYPE,  PRO_VALUE_TYPE_INT },
   { PRO_E_HOLESETS,                   ARRAY              }
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0    },  /* required for drilling */
   { "CLEAR_DIST",          1.0      },  /* required for drilling */
   { "SPINDLE_SPEED",       15000.0  }   /* required for drilling */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserCSinkgCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_DRILL,
                                       PRO_NCSEQ_HOLEMAKING, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserCSinkgCreate()", "UserCSinkgCreate", err );

 /*********************************************/
 /* Add elements specific for countersinking  */
 /*********************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserCSinkgCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_HOLEMAKING_TYPE:
		err = ProElementIntegerSet ( element, PRO_HOLE_MK_CSINK );
        ERROR_CHECK( "UserCSinkgCreate()", "ProElementIntegerSet", err );
        break;

     case PRO_E_MFG_HOLEMAKING_CYCLE_TYPE:
		err = ProElementIntegerSet ( element, PRO_HM_CYCLE_TYPE_STANDARD );
        ERROR_CHECK( "UserCSinkgCreate()", "ProElementIntegerSet", err );
        break;

     case PRO_E_HOLESETS:
        err = UserCsinkHolesetArrSet( csink_diam, element );
        ERROR_CHECK( "UserCSinkgCreate()", "UserCsinkHolesetArrSet", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserCSinkgCreate()", "UserCSinkgCreate", err );
        break;
   }
	
   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserCSinkgCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserCSinkgCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserCSinkgCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserDrillingCreate
Purpose  : Create a holemaking feature using element tree
\*====================================================================*/
ProError UserDrillingCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProSelection	   *axes,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProValueData           value_data;
 ProValue               value;
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_HOLEMAKING_TYPE,            PRO_VALUE_TYPE_INT },
   { PRO_E_MFG_HOLEMAKING_CYCLE_TYPE,  PRO_VALUE_TYPE_INT },
   { PRO_E_HOLESETS,                   ARRAY              }
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0    },  /* required for drilling */
   { "CLEAR_DIST",          1.0      },  /* required for drilling */
   { "SPINDLE_SPEED",       15000.0  }   /* required for drilling */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserDrillingCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_DRILL,
                                       PRO_NCSEQ_HOLEMAKING, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserDrillingCreate()", "UserNcSeqTreeCommonElementsAdd", err );

 /*********************************************/
 /* Add elements specific for drilling        */
 /*********************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserDrillingCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_HOLEMAKING_TYPE:
		err = ProElementIntegerSet ( element, PRO_HOLE_MK_DRILL );
        ERROR_CHECK( "UserDrillingCreate", "ProElementIntegerSet", err );
        break;

     case PRO_E_MFG_HOLEMAKING_CYCLE_TYPE:
		err = ProElementIntegerSet ( element, PRO_HM_CYCLE_TYPE_STANDARD );
        ERROR_CHECK( "UserDrillingCreate", "ProElementIntegerSet", err );
        break;

     case PRO_E_HOLESETS:
        err = UserDrillHolesetArrSet( axes, element );
        ERROR_CHECK( "UserDrillingCreate()", "UserDrillHolesetArrSet", 
                     err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserDrillingCreate()", "UserDrillingCreate", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserDrillingCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserDrillingCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserDrillingCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
Function : UserManualCycleCreate
Purpose  : Create a manual cycle feature using element tree
\*====================================================================*/
ProError UserManualCycleCreate (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane,
ProSelection	   seq_csys,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name 

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element = NULL;       /* Individual element */
 ProElement		seq_elem_tree = NULL; /* Entire tree        */
 ProFeature		seq_feature;
 int            	ii = 0, size = 0;
 int			n_dbl_params = 0;
 static ElemTable	seq_elem_table[] =  
 {
   { PRO_E_TOOL_MTN_ARR, ARRAY },
 };
 static MfgPrmDblValue	dbl_params[] =
 {
   { "CUT_FEED",            200.0    },  /* required for manual cycle */
   { "SPINDLE_SPEED",       15000.0  }   /* required for manual cycle */
 };

 n_dbl_params = sizeof( dbl_params ) / sizeof( MfgPrmDblValue );
		
 size = sizeof( seq_elem_table ) / sizeof( ElemTable );
   
 /*********************************************/
 /*  Allocate element tree                    */
 /*********************************************/
 err = ProElementAlloc( PRO_E_FEATURE_TREE, &seq_elem_tree );
 ERROR_CHECK( "UserManualCycleCreate", "ProElementAlloc()", err );
    
 /************************************************/
 /* Init elem tree with common sequence elements */
 /************************************************/
 err = UserNcSeqTreeCommonElementsAdd( mfg_model, 
                                       PRO_FEAT_MILL,
                                       PRO_NCSEQ_MANUAL_CYCLE_MILL, 
                                       feat_name, 
                                       operation, 
                                       retract_plane, 
                                       seq_csys, 
                                       head_num, 
                                       pocket_num, 
                                       tool_name, 
                                       dbl_params,
                                       n_dbl_params,
                                       NULL,
                                       0,
                                       seq_elem_tree );

 ERROR_CHECK( "UserManualCycleCreate()", "UserNcSeqTreeCommonElementsAdd", 
              err );

 /***************************************************/
 /* Add elements specific for manual cycle sequence */
 /***************************************************/
 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( seq_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserManualCycleCreate","ProElementAlloc()", err );

   switch ( seq_elem_table[ii].elem_type )
   {
     case PRO_E_TOOL_MTN_ARR:
        err = UserManualCycleMtnArrSet( element );
        ERROR_CHECK( "UserManualCycleCreate",
                     "UserManualCycleMtnArrSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserManualCycleCreate","UserManualCycleCreate()", err );
        break;
   }

   err = ProElemtreeElementAdd( seq_elem_tree, NULL, element );
   ERROR_CHECK( "UserManualCycleCreate", "ProElemtreeElementAdd()", err );
 }
 
 /*********************************************/
 /* Display element tree                      */
 /*********************************************/
 ProUtilElementtreePrint( seq_elem_tree, PRO_TEST_INFO_WINDOW, NULL );

 /*********************************************/
 /* Create feature                            */
 /*********************************************/
 err = UserMfgModelFeatureCreate( mfg_model, seq_elem_tree, &seq_feature );
 ERROR_CHECK( "UserManualCycleCreate", "UserMfgModelFeatureCreate()", err );

 err = ProElementFree( &seq_elem_tree );
 ERROR_CHECK( "UserManualCycleCreate", "ProElementFree()", err );

 return ( (int)err );
}

/*====================================================================*\
FUNCTION : UserNcsequenceCreate
PURPOSE  : Top level nc-sequence creation function
\*====================================================================*/
int UserNcsequenceCreate ()
{
 ProMdl		    mfg_model;
 ProError	    err = PRO_TK_NO_ERROR;
 ProAssembly	    assembly;
 ProSelection	    workcell;
 int		    num_sels;
 NcseqEnts	    entities;
 ProLine	    tool_name;
 ProMfgToolHeadType head_num = PRO_MFG_TOOL_HEAD_1;
 ProSelection	    *axes;
 ProSelection	    curve;
 ProSelection	    seq_sel;
 ProFeature         rough_seq;
 int		    pocket_num = 1;
 int		    n_params;
 static MfgPrmDblValue  end_mill_60x40_params[] =
 {
   { "CUTTER_DIAM",         60.0 },
   { "LENGTH",              40.0 }
 };
 static MfgPrmDblValue  drill_8mm_params[] =
 {
   { "CUTTER_DIAM",         8.0   },
   { "LENGTH",              75.0   },
   { "POINT_ANGLE",         118.0  }
 };
 static MfgPrmDblValue  end_mill_60x180_params[] =
 {
   { "CUTTER_DIAM",         60.0  },
   { "LENGTH",              180.0 }
 };
 static MfgPrmDblValue  end_mill_18x100_params[] =
 {
   { "CUTTER_DIAM",         18.0  },
   { "LENGTH",              100.0 }
 };
 static MfgPrmDblValue  end_mill_20x40_params[] =
 {
   { "CUTTER_DIAM",         20.0 },
   { "LENGTH",              40.0 }
 };

 static MfgPrmDblValue  csink_15mm_params[] =
 {
   { "CUTTER_DIAM",         15.0  },
   { "POINT_ANGLE",         90.0 },
   { "LENGTH",              50.0  },
 };


 err = ProMdlCurrentGet( &mfg_model );
 ERROR_CHECK( "UserNcsequenceCreate", "ProMdlCurrentGet", err );

 err = ProMfgAssemGet( (ProMfg)mfg_model, &assembly );
 ERROR_CHECK( "UserNcsequenceCreate", "ProMfgAssemGet", err );

 /*--------------------------------------------------------------------*\
    Search required references
 \*--------------------------------------------------------------------*/
 entities.oper_found = PRO_B_FALSE;
 entities.csys_found = PRO_B_FALSE;
 entities.retract_found = PRO_B_FALSE;
 entities.face_mill_wind_found = PRO_B_FALSE;
 entities.pocket_mill_wind_found = PRO_B_FALSE;
 entities.prof_mill_surf_found = PRO_B_FALSE;
 entities.traj_curve_found = PRO_B_FALSE;
 entities.model = (ProMfg)mfg_model;

 err = ProSolidFeatVisit( assembly, UserNcseqEntitiesCollect, NULL,
                          (ProAppData) &entities );

 /*--------------------------------------------------------------------*\
    Create features
 \*--------------------------------------------------------------------*/
 if ( entities.oper_found           && 
      entities.retract_found        &&
      entities.csys_found           &&
      entities.traj_curve           &&
      entities.face_mill_wind_found &&
      entities.prof_mill_surf_found &&
      entities.pocket_mill_wind_found )
 {
   err = UserOperWorkcellGet( entities.operation, &workcell );
   ERROR_CHECK( "UserNcsequenceCreate", "UserOperWorkcellGet", err );

   /*------------------------------------------------------------------*\
      Facing sequence
   \*------------------------------------------------------------------*/
   ProStringToWstring( tool_name, "FLAT_MILL_60MM" );
   n_params = sizeof( end_mill_60x40_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_END_MILL, tool_name, 
                              end_mill_60x40_params, n_params, 
                              PRO_UNITLENGTH_MM, PRO_B_TRUE, &pocket_num );
   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );

   err = UserFacingCreate( (ProMfg)mfg_model,
                           L"FACING_W_D60_CUTTER", 
                           entities.operation, 
                           entities.retract_plane,
                           entities.csys, 
                           entities.face_mill_window, 
                           head_num,
                           pocket_num,
                           tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserFacingCreate", err );

   /*------------------------------------------------------------------*\
      Countersink sequence
   \*------------------------------------------------------------------*/
   ProStringToWstring( tool_name, "CSINK_15MM" );
   n_params = sizeof( csink_15mm_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_CSINK, tool_name, 
                              csink_15mm_params, n_params, PRO_UNITLENGTH_MM, 
                              PRO_B_TRUE, &pocket_num );

   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );

   err = UserCSinkgCreate( (ProMfg)mfg_model,
                           L"COUNTERSINK_D9", 
                           entities.operation, 
                           entities.retract_plane,
                           entities.csys, 
                           9.,
                           head_num,
                           pocket_num,
                           tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserCSinkgCreate", err );

   /*------------------------------------------------------------------*\
      Drilling sequence
   \*------------------------------------------------------------------*/
   ProStringToWstring( tool_name, "DRILL_8MM" );
   n_params = sizeof( drill_8mm_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_DRILL, tool_name, 
                              drill_8mm_params, n_params, PRO_UNITLENGTH_MM, 
                              PRO_B_TRUE, &pocket_num );

   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );

   err = UserCollectAxesToDrill( assembly, &axes );
   ERROR_CHECK( "UserNcsequenceCreate", "UserCollectAxesToDrill", err );

   err = UserDrillingCreate( (ProMfg)mfg_model,
                             L"DRILLING_W_D8_DRILL", 
                             entities.operation, 
                             entities.retract_plane,
                             entities.csys, 
                             axes,
                             head_num,
                             pocket_num,
                             tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserDrillingCreate", err );

   /*------------------------------------------------------------------*\
      Trajectory sequence (tool motion based trajectory)
   \*------------------------------------------------------------------*/
   ProStringToWstring( tool_name, "END_MILL_65MM" );
   n_params = sizeof( end_mill_60x180_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_END_MILL, tool_name, 
                              end_mill_60x180_params, n_params,
                              PRO_UNITLENGTH_MM, PRO_B_TRUE, &pocket_num );
   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );

   err = UserTrajectoryCreate( (ProMfg)mfg_model,
                                L"TRAJECTORY_W_D60_MILL", 
                                entities.operation, 
                                entities.retract_plane,
                                entities.csys, 
                                entities.traj_curve, 
                                head_num,
                                pocket_num,
                                tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserTrajectoryCreate", err );

   /*------------------------------------------------------------------*\
      2-axis trajectory sequence (curve trajectory)
   \*------------------------------------------------------------------*/
   err = UserCurveTrajCreate( (ProMfg)mfg_model,
                              L"CURVE_TRAJECTORY_W_D60_MILL", 
                              entities.operation, 
                              entities.retract_plane,
                              entities.csys, 
                              entities.traj_curve, 
                              head_num,
                              pocket_num,
                              tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserTrajectoryCreate", err );

   /*------------------------------------------------------------------*\
      Roughing sequence
   \*------------------------------------------------------------------*/
   err = UserRoughingCreate( (ProMfg)mfg_model,
                             L"ROUGHING_W_D60_MILL", 
                             entities.operation, 
                             entities.retract_plane,
                             entities.csys, 
                             entities.pocket_mill_window, 
                             head_num,
                             pocket_num,
                             tool_name,
                             &rough_seq );
   ERROR_CHECK( "UserNcsequenceCreate", "UserRoughingCreate", err );

   /*------------------------------------------------------------------*\
      Re-Roughing sequence
   \*------------------------------------------------------------------*/
   err = ProSelectionAlloc( NULL, &rough_seq, &seq_sel );
   ERROR_CHECK( "UserNcseqEntitiesCollect", "ProSelectionAlloc()", err );

   ProStringToWstring( tool_name, "END_MILL_20MM" );
   n_params = sizeof( end_mill_20x40_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_END_MILL, tool_name, 
                              end_mill_20x40_params, n_params, 
                              PRO_UNITLENGTH_MM, PRO_B_TRUE, &pocket_num );
   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );
   err = UserReRoughingCreate( (ProMfg)mfg_model,
                               L"RE-ROUGHING_W_D20_MILL", 
                               entities.operation, 
                               entities.retract_plane,
                               entities.csys, 
                               seq_sel,
                               head_num,
                               pocket_num,
                               tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserReRoughingCreate", err );

   /*------------------------------------------------------------------*\
      Finishing sequence
   \*------------------------------------------------------------------*/
   err = UserFinishingCreate( (ProMfg)mfg_model,
                              L"FINISHING_W_D20_MILL", 
                              entities.operation, 
                              entities.retract_plane,
                              entities.csys, 
                              entities.pocket_mill_window, 
                              head_num,
                              pocket_num,
                              tool_name );
   ERROR_CHECK( "UserNcsequenceCreate", "UserFinishingCreate", err );

   /*------------------------------------------------------------------*\
      Profile milling sequence
   \*------------------------------------------------------------------*/
   ProStringToWstring( tool_name, "END_MILL_18MM" );
   n_params = sizeof( end_mill_18x100_params )/sizeof( MfgPrmDblValue );

   err = UserWorkcellToolAdd( mfg_model, workcell, head_num,  
                              PRO_TOOL_END_MILL, tool_name, 
                              end_mill_18x100_params, n_params,
                              PRO_UNITLENGTH_MM, PRO_B_TRUE, &pocket_num );
   ERROR_CHECK( "UserNcsequenceCreate", "UserWorkcellToolAdd", err );

   err = UserProfilingCreate( (ProMfg)mfg_model,
                              L"PROFILING_W_D18_MILL", 
                              entities.operation, 
                              entities.retract_plane,
                              entities.csys, 
                              entities.prof_mill_surf, 
                              head_num,
                              pocket_num,
                              tool_name,
                              &rough_seq );
   ERROR_CHECK( "UserNcsequenceCreate", "UserProfilingCreate", err );

   /*------------------------------------------------------------------*\
      Manual cycle sequence
   \*------------------------------------------------------------------*/
   err = UserManualCycleCreate( (ProMfg)mfg_model,
                                L"MANUAL_CYCLE_W_NO_TOOL", 
                                entities.operation, 
                                entities.retract_plane,
                                entities.csys, 
                                head_num,
                                -1,
                                NULL );
   ERROR_CHECK( "UserNcsequenceCreate", "UserManualCycleCreate", err );

 }
 else
 {
   if ( !entities.retract_found )
     ProTKFprintf( stderr, "A suitable retract plane was not found\n" );

   if ( !entities.oper_found )
     ProTKFprintf( stderr, "A suitable operation was not found\n" );

   if ( !entities.csys_found )
     ProTKFprintf( stderr, "A suitable csys was not found\n" );

   if ( !entities.face_mill_wind_found )
     ProTKFprintf( stderr, "A suitable mill window was not found\n" );

   if ( !entities.pocket_mill_wind_found )
     ProTKFprintf( stderr, "A suitable mill window was not found\n" );

   if ( !entities.prof_mill_surf_found )
     ProTKFprintf( stderr, "A suitable mill surface was not found\n" );
 }
    
 return ((int)err);
}