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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProSurface.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProSelection.h>
#include <ProSolid.h>
#include <ProAsmcomp.h>
#include <ProEdge.h>
#include <ProAxis.h>
#include <ProCsys.h>
#include <ProCurve.h>
#include <ProPoint.h>
#include <ProGeomitem.h>
#include <ProNcseq.h>
#include <UtilString.h>
/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "UtilMath.h"
#include "UtilVisit.h"
#include "UtilCollect.h"
#include "UtilTypes.h"

/*--------------------------------------------------------------------*\
Application data
\*--------------------------------------------------------------------*/

int multiCadCopy_count = 1;
typedef struct 
{
    ProAppData  app_data;       /* The caller's app_data */
    ProFunction action;         /* The caller's action function */
} AsmComp_data_t ;

/*--------------------------------------------------------------------*\
    We need our own app_data to pass to ProUtilAsmCompVisit() which
    contains both the app_data and the action function pointer input to
    this function, plus our own context data so that OUR action function
    has all it needs to call the user's action function.
\*--------------------------------------------------------------------*/

typedef ProError (*ProTestAsmTravAction) (ProAsmcomppath*, ProAppData);

typedef struct 
{
    ProAppData     app_data;	/* The caller's app_data */
    ProTestAsmTravAction    action;	/* The caller's action function */
    ProAsmcomppath comp_path;	/* The current component path */
} AsmTrav_data_t ;

/*====================================================================*\
    FUNCTION :	ProUtilAsmcompVisit()
    PURPOSE  :	Visit function for components of an assembly
\*====================================================================*/
ProError ProUtilAsmcompVisit(
    ProAssembly assembly,
    ProFunction action,
    ProAppData  app_data )
{
    ProError status;

/*--------------------------------------------------------------------*\
    Visit all the features, using a filter to see only assembly components
\*--------------------------------------------------------------------*/
    status = ProSolidFeatVisit(assembly, (ProFeatureVisitAction)action,
		(ProFeatureFilterAction)ProUtilAsmcompFilterAction, app_data);
    TEST_CALL_REPORT("ProSolidFeatVisit()", "ProUtilAsmcompVisit()",
                                status, status != PRO_TK_NO_ERROR);
    
    return(status);
}

/*====================================================================*\
    FUNCTION :	ProUtilFeatvisVisit()
    PURPOSE  :	Visit function for visible features
\*====================================================================*/
ProError ProUtilFeatvisVisit(
    ProSolid	solid,
    ProFunction action,
    ProAppData  app_data )
{
    ProError status;

/*--------------------------------------------------------------------*\
    Visit all the features, using a filter to see only assembly components
\*--------------------------------------------------------------------*/
    status = ProSolidFeatVisit(solid, (ProFeatureVisitAction)action,
				(ProFeatureFilterAction)ProUtilFeatvisFilterAction, app_data);
    TEST_CALL_REPORT("ProSolidFeatVisit()", "ProUtilFeatvisVisit()",
                                status, status != PRO_TK_NO_ERROR);
    
    return(status);
}

/*====================================================================*\
    FUNCTION :	ProUtilGeomitemactiveVisit()
    PURPOSE  :	Visit function for active geomitems
\*====================================================================*/
ProError ProUtilGeomitemactiveVisit( 
    ProFeature *p_feature,
    ProType item_type,
    ProFunction action,
    ProAppData  app_data)
{
    ProError status;

/*--------------------------------------------------------------------*\
    Visit all the features, using a filter to see only assembly components
\*--------------------------------------------------------------------*/
    status = ProFeatureGeomitemVisit(p_feature, item_type,
	    (ProGeomitemAction)action,
	     (ProGeomitemFilter)ProUtilGeomitemactiveFilterAction, app_data);
    TEST_CALL_REPORT("ProFeatureGeomitemVisit()", 
	"ProUtilGeomitemactiveVisit()",
        status, status != PRO_TK_NO_ERROR);
   
    return status; 
}


/*====================================================================*\
    FUNCTION :	ProUtilAsmTravAction()
    PURPOSE  :	Action function to be called for features inside
		ProUtilAsmTraverse() to recursively visit features which
		are assemblt components.
\*====================================================================*/
ProError ProUtilAsmTravAction(
    ProFeature *component,
    ProError instatus,
    ProAppData app_data )
{
    ProError status;
    ProSolid model;
    AsmTrav_data_t *asm_data = (AsmTrav_data_t*)app_data;
    ProMdlType model_type;

/*--------------------------------------------------------------------*\
    Increment the component path
\*--------------------------------------------------------------------*/
    asm_data->comp_path.comp_id_table[asm_data->comp_path.table_num++] =
		component->id;
    asm_data->comp_path.comp_id_table[asm_data->comp_path.table_num] = -1;
    
/*--------------------------------------------------------------------*\
    Get the ProMdl for this assembly component
\*--------------------------------------------------------------------*/
    status = ProAsmcompMdlGet(component, (ProMdl *) &model);
    TEST_CALL_REPORT("ProAsmcompMdlGet()", "ProUtilAsmTravAction()",
                                status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Call the action function for this component, with the user's app_data
\*--------------------------------------------------------------------*/
    status = (*asm_data->action)
        (&asm_data->comp_path, asm_data->app_data);

/*--------------------------------------------------------------------*\
    If the model is an assembly, visit its components recursively
\*--------------------------------------------------------------------*/

    ProMdlTypeGet(model, &model_type);
    TEST_CALL_REPORT("ProMdlTypeGet()", "ProUtilAsmTravAction()",
                                status, status != PRO_TK_NO_ERROR);

    if(model_type == PRO_MDL_ASSEMBLY)
	ProUtilAsmcompVisit((ProAssembly)model,
			    (ProFunction)ProUtilAsmTravAction,app_data);

/*--------------------------------------------------------------------*\
    Decrement the component path
\*--------------------------------------------------------------------*/
    asm_data->comp_path.comp_id_table[asm_data->comp_path.table_num--] = -1;

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProUtilAsmTraverse()
    PURPOSE  :	Visit function for components of an assembly at ALL levels
\*====================================================================*/
ProError ProUtilAsmTraverse(
    ProAssembly assembly,
    ProFunction action,
    ProAppData app_data)
{
    ProError status;
    AsmTrav_data_t asm_data;
    ProIdTable comp_id_table;

/*--------------------------------------------------------------------*\
    Initialize our asm_data
\*--------------------------------------------------------------------*/
    asm_data.app_data = app_data;
    asm_data.action = (ProTestAsmTravAction)action;
    comp_id_table[0] = -1;
    status = ProAsmcomppathInit(assembly, comp_id_table, 0, 
                    &asm_data.comp_path);
    TEST_CALL_REPORT("ProAsmcomppathInit()", "ProUtilAsmTraverse()",
				status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Visit the components are this level
\*--------------------------------------------------------------------*/
    ProUtilAsmcompVisit(assembly, (ProFunction)ProUtilAsmTravAction,
						(ProAppData)&asm_data);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :  ProUtilAsmFeatsTraverse()
    PURPOSE  :  Visit function for features of an assembly at *ALL* levels
\*====================================================================*/
ProError ProUtilAsmFeatsTraverse(
    ProAssembly assembly,
    ProFunction action,
    ProAppData app_data)
{
    ProError status;
    AsmTrav_data_t asm_data;
    ProIdTable comp_id_table;
 
/*--------------------------------------------------------------------*\
    Initialize our asm_data
\*--------------------------------------------------------------------*/
    asm_data.app_data = app_data;
    asm_data.action = (ProTestAsmTravAction) action;
    comp_id_table[0] = -1;
    status = ProAsmcomppathInit(assembly, comp_id_table, 0,
                    &asm_data.comp_path);
    TEST_CALL_REPORT("ProAsmcomppathInit()", "ProUtilAsmTraverse()",
                                status, status != PRO_TK_NO_ERROR);
 
/*--------------------------------------------------------------------*\
    Visit the components are this level
\*--------------------------------------------------------------------*/
    ProUtilAsmcompVisit(assembly, (ProFunction) ProUtilAsmTravAction,
                                                (ProAppData)&asm_data);
 
    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
    FUNCTION :	ProUtilAsmcompFilterAction()
    PURPOSE  :	A filter used by ProUtilAsmCompVisit() to visit
		features which are assembly components
\*====================================================================*/
ProError ProUtilAsmcompFilterAction(
    ProFeature *feature,
    ProAppData app_data)
{
    ProError status;
    ProFeattype ftype;

/*--------------------------------------------------------------------*\
    Get the feature type
\*--------------------------------------------------------------------*/
    status = ProFeatureTypeGet(feature, &ftype);

/*--------------------------------------------------------------------*\
    If the feature is an assembly component,
	return NO ERROR,
    else
	return CONTINUE
\*--------------------------------------------------------------------*/
    if(ftype == PRO_FEAT_COMPONENT)
	return(PRO_TK_NO_ERROR);
    return(PRO_TK_CONTINUE);
}

/*=========================================================================*\
    Function:	ProUtilFeatvisFilterAction()
    Purpose:	Filter function for ProSolidFeatVisit, allow to visit only 
		visible features
    Returns:	PRO_TK_NO_ERROR - feature visible
		PRO_TK_CONTINUE - otherwise
\*=========================================================================*/
ProError ProUtilFeatvisFilterAction(
    ProFeature *p_feature,	/* In : the feature */
    ProAppData app_data)	/* In : appdata (not used) */
{
    ProError status;
    ProBoolean visible;

    status = ProFeatureVisibilityGet(p_feature, &visible);
    TEST_CALL_REPORT("ProFeatureVisibilityGet()", 
				    "ProUtilFeatvisFilterAction()", 
				    status, status != PRO_TK_NO_ERROR);
    if (status == PRO_TK_NO_ERROR)
	status = (visible == PRO_B_TRUE ? PRO_TK_NO_ERROR : PRO_TK_CONTINUE);

    return (status);
}


/*=========================================================================*\
    Function:	ProUtilByNameFilterAction()
    Purpose:	Allow to visit only modelitem with a specified name
    Returns:	PRO_TK_NO_ERROR - success;
		PRO_TK_CONTINUE - no valid modelitem found
\*=========================================================================*/
ProError ProUtilByNameFilterAction(
    ProModelitem *p_modelitem,	    /* In : The modelitem */
    FindByName   *p_findbyname)	    /* In : The find structure */
{
    ProName  name;
    ProError status;

    status = ProModelitemNameGet(p_modelitem, name);
    TEST_CALL_REPORT("ProModelitemNameGet()", 
				    "ProUtilFindByNameFilterAction()", 
	    status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);
    if (status == PRO_TK_NO_ERROR) 
    {
	if (ProUtilWstrCmp(p_findbyname->name, name)==0)
	    status = PRO_TK_NO_ERROR;
	else 
	    status = PRO_TK_CONTINUE;
    }
    else if (status == PRO_TK_E_NOT_FOUND)
	status = PRO_TK_CONTINUE;

    return (status);
}

/*=========================================================================*\
    Function:	ProUtilFeatvisByNameFilterAction()
    Purpose:	Allow to visit only visible features with a specified name
    Returns:	PRO_TK_NO_ERROR - success;
		PRO_TK_CONTINUE - no valid feature found found
\*=========================================================================*/
ProError ProUtilFeatvisByNameFilterAction(
    ProFeature   *p_feature,	    /* In : The feature */
    FindByName   *p_findbyname)	    /* In : The find structure */
{
    ProError  status;

    status = ProUtilFeatvisFilterAction(p_feature, NULL);
    if (status == PRO_TK_NO_ERROR)
	status = ProUtilByNameFilterAction((ProModelitem*)p_feature, 
	    p_findbyname);
	
    return (status);
}

/*=========================================================================*\
    Function:	ProUtilGeomitemactiveFilterAction()
    Purpose:	Filter function for ProFeatureGeomitemVisit, allow to visit 
		only active geomitems
    Returns:	PRO_TK_NO_ERROR - feature visible
		PRO_TK_CONTINUE - otherwise
\*=========================================================================*/
ProError ProUtilGeomitemactiveFilterAction(
    ProGeomitem *p_geomitem,	/* In : the geomitem */
    ProAppData app_data)	/* In : appdata (not used) */
{
    ProBoolean test;
    ProError status;

    TEST_CALL_REPORT( "ProGeomitemFilter", "ProUtilGeomitemactiveFilterAction",
	PRO_TK_NO_ERROR, 0 );
    status = ProGeomitemIsInactive(p_geomitem, &test);
    TEST_CALL_REPORT("ProGeomitemIsInactive()", 
	"ProUtilGeomitemactiveFilterAction()", 
        status, status != PRO_TK_NO_ERROR);
    return (test != PRO_B_TRUE ? PRO_TK_NO_ERROR : PRO_TK_CONTINUE);
}


/*=========================================================================*\
    Function:   ProUtilAxisByVectorFilterAction()
    Purpose:    Allow to visit only axis which parallel (perpendicular)
                to a vector
    Returns:    PRO_TK_NO_ERROR - success;
                PRO_TK_CONTINUE - no valid axis found
\*=========================================================================*/
ProError ProUtilAxisByVectorFilterAction(
    ProAxis axis,                               /* In : The Axis */
    CollectAxisByVector *p_find_by_vector)      /* In : find data */
{
    ProGeomitemdata  *p_gi_data;
    Pro3dPnt         vec;
    double           dot;
    ProError         status = PRO_TK_CONTINUE;


    TEST_CALL_REPORT( "ProAxisFilterAction", "ProUtilAxisByVectorFilterAction",
	PRO_TK_NO_ERROR, 0 );

    status = ProAxisDataGet(axis, &p_gi_data);
    TEST_CALL_REPORT("ProAxisDataGet()", "ProUtilAxisByVectorFilterAction()",
                                    status, status != PRO_TK_NO_ERROR);
    ProUtilVectorDiff(p_gi_data->data.p_curve_data->line.end2,
                      p_gi_data->data.p_curve_data->line.end1, vec);
    status = ProGeomitemdataFree(&p_gi_data);
    TEST_CALL_REPORT("ProGeomitemdataFree()",
        "ProUtilAxisByVectorFilterAction()", status, status != PRO_TK_NO_ERROR);
    ProUtilVectorNormalize(vec, vec);
    dot = fabs(ProUtilVectorDot(vec, p_find_by_vector->vec));
    if ((p_find_by_vector->option==USER_PARALLEL && 1-dot<EPSM6) ||
         (p_find_by_vector->option==USER_PERPENDICULAR && dot<EPSM6))
         status = PRO_TK_NO_ERROR;
    else
         status = PRO_TK_CONTINUE;
    return (status);
}

/*=========================================================================*\
    Function:	ProUtilCollectDtmCurveFeatFilter()
    Purpose:	Allow to visit only dtm curve features
    Returns:	PRO_TK_NO_ERROR - success;
		PRO_TK_CONTINUE - no valid feature found found
\*=========================================================================*/
ProError ProUtilCollectDtmCurveFeatFilter(
    ProFeature   *p_feature,	    /* In : The feature */
    ProAppData   app_data)	    /* In : The find structure */
{
    ProError  status;
    ProFeattype ftype;
    
    TEST_CALL_REPORT( "ProFeatureFilterAction", 
        "ProUtilCollectDtmCurveFeatFilter",
	PRO_TK_NO_ERROR, 0 );

    status = ProFeatureTypeGet(p_feature, &ftype);
    TEST_CALL_REPORT("ProFeatureTypeGet()", "ProUtilCollectDtmCurveFeatFilter()",
			    status, status != PRO_TK_NO_ERROR);

    return(ftype == PRO_FEAT_CURVE ? PRO_TK_NO_ERROR : PRO_TK_CONTINUE);
}

/*====================================================================*\
    FUNCTION :	ProUtilCollectDtmPointFeatFilter()
    PURPOSE  :	A filter used to visit only Datum Points features
\*====================================================================*/
ProError ProUtilCollectDtmPointFeatFilter(
    ProFeature *feature,
    ProAppData app_data)
{
    ProError status;
    ProFeattype ftype;

/*--------------------------------------------------------------------*\
    Get the feature type
\*--------------------------------------------------------------------*/
    status = ProFeatureTypeGet(feature, &ftype);

/*--------------------------------------------------------------------*\
    If the feature is Datum Point,
	return NO ERROR,
    else
	return CONTINUE
\*--------------------------------------------------------------------*/
    if(ftype == PRO_FEAT_DATUM_POINT)
	return(PRO_TK_NO_ERROR);
    return(PRO_TK_CONTINUE);
}


/*=========================================================================*\
    Function:	ProUtilCollectDtmCurveFeatFilter()
    Purpose:	Allow to visit only dtm curve features
    Returns:	PRO_TK_NO_ERROR - success;
		PRO_TK_CONTINUE - no valid feature found found
\*=========================================================================*/
ProError ProUtilCollectNCSeqFeatFilter(
    ProFeature   *p_feat,	    /* In : The feature */
    ProAppData   tmp_p_nc_seq)	    /* In : The find structure */
{
    ProError status;
    ProBoolean is_nc_seq;
    
    TEST_CALL_REPORT( "ProFeatureFilterAction", "ProUtilCollectNCSeqFeatFilter",
	PRO_TK_NO_ERROR, 0 );

    status = ProFeatureIsNcseq(p_feat, &is_nc_seq);
    TEST_CALL_REPORT("ProFeatureIsNcseq()",
                        "ProTestFeatFilterNcseq()", status,
                        (status != PRO_TK_NO_ERROR));

    return (is_nc_seq == PRO_B_TRUE? PRO_TK_NO_ERROR : PRO_TK_CONTINUE);

}

/*=========================================================================*\
    Function:	ProUtilGeomitemByNameFilterAction()
    Purpose:	Allow to visit only geomitem with a specified name
    Returns:	PRO_TK_NO_ERROR - success;
		PRO_TK_CONTINUE - no valid modelitem found
\*=========================================================================*/
ProError ProUtilGeomitemByNameFilterAction(
    ProAppData geomitem,	    /* In : The geomitem */
    FindByName   *p_findbyname)	    /* In : The find structure */
{
    ProName  name;
    ProError status;
    ProModelitem modelitem = p_findbyname->p_modelitem[0];

    switch (modelitem.type)
    {
	case PRO_CSYS:
	    status = ProCsysToGeomitem((ProSolid)modelitem.owner, 
		(ProCsys)geomitem, &modelitem);
	    TEST_CALL_REPORT("ProCsysToGeomitem()", 
		"ProUtilGeomitemByNameFilterAction()", 
		status, status != PRO_TK_NO_ERROR);
	    break;
	case PRO_AXIS:
	    status = ProAxisToGeomitem((ProSolid)modelitem.owner, 
		(ProAxis)geomitem, &modelitem);
	    TEST_CALL_REPORT("ProAxisToGeomitem()", 
		"ProUtilGeomitemByNameFilterAction()", 
		status, status != PRO_TK_NO_ERROR);
	    break;
	case PRO_SURFACE:
	    status = ProSurfaceToGeomitem((ProSolid)modelitem.owner, 
		(ProSurface)geomitem, &modelitem);
	    TEST_CALL_REPORT("ProSurfaceToGeomitem()", 
		"ProUtilGeomitemByNameFilterAction()", 
		status, status != PRO_TK_NO_ERROR);
	    break;
	default:
	    status = PRO_TK_GENERAL_ERROR;
    }
    
    if (status == PRO_TK_NO_ERROR)
    {
	status = ProModelitemNameGet(&modelitem, name);
	TEST_CALL_REPORT("ProModelitemNameGet()", 
		"ProUtilGeomitemByNameFilterAction()", status,
		status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);
    }
    if (status == PRO_TK_NO_ERROR) 
    {
	if (ProUtilWstrCmp(p_findbyname->name, name)==0)
	    status = PRO_TK_NO_ERROR;
	else 
	    status = PRO_TK_CONTINUE;
    }
    else if (status == PRO_TK_E_NOT_FOUND)
	status = PRO_TK_CONTINUE;

    return (status);
}


/*============================================================================*\
    FUNCTION : ProUtilMultiCADFileInfoWrite	
    PURPOSE  : Writes model info in file
\*============================================================================*/
ProError ProUtilMultiCADFileInfoWrite(ProMdl model, FILE *MultiCADInfo_fp)
{
	ProError   status;
 	ProMdlType modelType;
	char       c_buff[PRO_PATH_SIZE], mdl_cext[PRO_MDLEXTENSION_SIZE];
	char       mdl_cname[PRO_PATH_SIZE];
	ProMdlType mdl_type;
	ProMdlName mdl_name, newName;
	ProMdl     newMdl;
	ProPath    mdl_path;
	ProMdlExtension mdl_ext;
	ProMdlfileType  fileType;



	/* ProMdlDataGet() is deprecated in creo3, use following functions to get model info. */
    /* Gets Multi-CAD file type */
	status = ProMdlMdlnameGet(model, mdl_name);
	TEST_CALL_REPORT( "ProMdlMdlnameGet()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);

	ProWstringToString(mdl_cname, mdl_name);
	ProTKFprintf (MultiCADInfo_fp,"      ++ Model name: %s \n", mdl_cname);

    /* Gets creo file type */
	status = ProMdlTypeGet(model,  &mdl_type);
	TEST_CALL_REPORT( "ProMdlTypeGet()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);

	status = (ProError) ProUtilObjtypeStr((ProType)mdl_type, c_buff);
	TEST_CALL_REPORT( "ProUtilObjtypeStr()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);

	ProTKFprintf (MultiCADInfo_fp,"      ++ Model Type: %s \n", c_buff);

    /* Gets path of input model */
	status = ProMdlDirectoryPathGet(model, mdl_path);
	TEST_CALL_REPORT( "ProMdlDirectoryPathGet()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);
	
	ProWstringToString(c_buff, mdl_path);
	ProTKFprintf (MultiCADInfo_fp,"      ++ Model path: %s \n", c_buff);

	/* Gets Multi-CAD file extention */ 
	status = ProMdlExtensionGet(model, mdl_ext);
	TEST_CALL_REPORT( "ProMdlExtensionGet()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);

	ProWstringToString(mdl_cext, mdl_ext);
	ProTKFprintf (MultiCADInfo_fp,"      ++ Model extention: %s \n", mdl_cext);

    /* Gets Multi-CAD file type */
	status = ProMdlFiletypeGet (model, (ProMdlfileType*) &fileType);
	TEST_CALL_REPORT("ProMdlFiletypeGet()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);
	
	status = (ProError)ProUtilMdlfileTypeStr(fileType, c_buff);
	TEST_CALL_REPORT( "ProUtilMdlfileTypeStr()", "ProUtilMultiCADFileInfoWrite()", 
			status, status != PRO_TK_NO_ERROR);

	ProTKFprintf (MultiCADInfo_fp,"      ++ Model File Type: %s \n", c_buff);

	/* In Creo3 ProMdlnameCopy() is not different from ProMdlCopy() and    
	   is added to provide consistency in future releases when it will  
	   be expanded to support MULTI-CAD assemblies. */
    
	ProTKSprintf (c_buff,"new_name%d", multiCadCopy_count);
	multiCadCopy_count++;
        
	strcat(c_buff,mdl_cname);
	ProStringToWstring (newName, c_buff);
	status = ProMdlnameCopy(model, newName, &newMdl);
	TEST_CALL_REPORT( "ProMdlnameCopy()", "ProMultiCADFileInfo()", 
			status, status != PRO_TK_NO_ERROR && status != PRO_TK_UNSUPPORTED);
	if(status == PRO_TK_UNSUPPORTED)
	{
		ProTKFprintf (MultiCADInfo_fp,
			     "      ++ ProMdlnameCopy is not supported for this file \n");
	}
	ProTKFprintf (MultiCADInfo_fp,"\n");

	return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
    FUNCTION : ProUtilMultiCADFilterAction	
    PURPOSE  : Filters PRO_FEAT_COMPONENT for ProSolidFeatVisit
\*============================================================================*/

ProError ProUtilMultiCADFilterAction(ProFeature *feature, ProAppData info_file)
{
  ProError    status;
  ProFeattype ftype;

  status = ProFeatureTypeGet(feature, &ftype);
  TEST_CALL_REPORT( "ProFeatureTypeGet()", "ProUtilMultiCADFilterAction()", 
		status, status != PRO_TK_NO_ERROR);

  if(ftype == PRO_FEAT_COMPONENT)
    return(PRO_TK_NO_ERROR);

  return(PRO_TK_CONTINUE);
}

/*============================================================================*\
    FUNCTION : ProUtilMultiCADVisitAction	
    PURPOSE  : Action function for ProSolidFeatVisit
\*============================================================================*/
ProError ProUtilMultiCADVisitAction(ProFeature *feat, 
									ProError visit_status, ProAppData appdata)
{
	ProError   status;
 	ProMdl     model;
 	ProMdlType mdl_type;
	char       mdl_cname[PRO_MDLNAME_SIZE], c_buff[PRO_MDLNAME_SIZE];
	
	ProMdlfileType   comp_type;
	ProFamilyMdlName comp_name;
	
	FILE  *MultiCADInfo_fp = (FILE *) appdata;

	if (visit_status == PRO_TK_NO_ERROR)
	{
        /* Gets Multi-CAD components name and type */
		status = ProAsmcompMdlMdlnameGet((ProAsmcomp *)feat, &comp_type, comp_name);
		TEST_CALL_REPORT ( "ProAsmcompMdlMdlnameGet()", "ProUtilMultiCADVisitAction()", 
			                status, status != PRO_TK_NO_ERROR );

		ProWstringToString(mdl_cname, comp_name);
		ProTKFprintf (MultiCADInfo_fp,"    ++ Component name: %s \n", mdl_cname);

		status = (ProError)ProUtilMdlfileTypeStr(comp_type, c_buff);
		TEST_CALL_REPORT( "ProUtilMdlfileTypeStr()", "ProUtilMultiCADVisitAction()", 
					       status, status != PRO_TK_NO_ERROR);
		ProTKFprintf (MultiCADInfo_fp,"    ++ Component type: %s \n", c_buff);

		status = ProAsmcompMdlGet((ProAsmcomp *)feat, (ProMdl *) &model);
		TEST_CALL_REPORT("ProAsmcompMdlGet", "ProUtilMultiCADVisitAction()", status, 
			              status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

		if(status == PRO_TK_NO_ERROR)
		{
			status = ProUtilMultiCADFileInfoWrite(model, MultiCADInfo_fp);
            
            /* Gets creo model type */
			status = ProMdlTypeGet(model,  &mdl_type);
			TEST_CALL_REPORT( "ProMdlTypeGet()", "ProUtilMultiCADFileInfoWrite()", 
							   status, status != PRO_TK_NO_ERROR);

			if(mdl_type == PRO_MDL_ASSEMBLY)
			{
                /* Visits sub assembly and components */
				status = ProSolidFeatVisit ((ProSolid)model, 
					                        (ProFeatureVisitAction)ProUtilMultiCADVisitAction,
					                        (ProFeatureFilterAction)ProUtilMultiCADFilterAction,
                                             MultiCADInfo_fp);
				TEST_CALL_REPORT("ProSolidFeatVisit_VisitFeatsOfTHA", 
					             "ProUtilMultiCADVisitAction()", status, 
								 status != PRO_TK_NO_ERROR );
			}
		}
	}

	return (PRO_TK_NO_ERROR);
}


/*============================================================================*\
    FUNCTION : ProUtilMultiCADFileInfoWrite	
    PURPOSE  : Writes model info in file
\*============================================================================*/
ProError ProUtilMultiCADFileInfo(ProMdl model, FILE *MultiCADInfo_fp)
{
	ProError status;

	status = ProUtilMultiCADFileInfoWrite(model, MultiCADInfo_fp);
	TEST_CALL_REPORT( "ProUtilMultiCADFileInfo()", "ProMultiCADFileInfo()", 
			status, status != PRO_TK_NO_ERROR);

	status = ProSolidFeatVisit ((ProSolid)model, (ProFeatureVisitAction)ProUtilMultiCADVisitAction, 
							(ProFeatureFilterAction) ProUtilMultiCADFilterAction, MultiCADInfo_fp);
	TEST_CALL_REPORT("ProSolidFeatVisit()", "ProMultiCADFileInfo()", status, 
						(status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND));

	return (PRO_TK_NO_ERROR);
}