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


#include <ProToolkit.h>
#include <ProAsmcomp.h>
#include <ProMessage.h>
#include <ProSolid.h>
#include <ProArray.h>
#include <ProPopupmenu.h>
#include <ProMenuBar.h>
#include <ProSelection.h>
#include <PTApplsUnicodeUtils.h>
#include <ProModelitem.h>
#include <ProUtil.h>
#include <UtilFiles.h>
#include <TestError.h>
#include <ProSelbuffer.h>

#include <UtilString.h>

#define MSGFIL L##"msg_ugasmcomp.txt"

/*-----------------------------------------------------------------*\
	Prototypes
\*-----------------------------------------------------------------*/
ProError  UserAsmcompConstraintsHighlight (ProAsmcomp* asmcomp);
ProError UserOpenComponent (ProSolid* solid);

void UserConstraintTypeToString (ProAsmcompConstrType type, 
								  char* type_string);
ProError UgSelectAsmIntent(ProAssembly asm_model, ProSolid comp_model, ProType constr_type, ProAsmcompconstraint** constraints);



/*=====================================================================*\
FUNCTION: UserAssembleByDatums
PURPOSE:  Assemble a component by aligning named datums.	
\*=====================================================================*/
ProError UserAssembleByDatums (ProAssembly asm_model, ProSolid comp_model)
{
	ProError status;
	ProName asm_datums [3];
	ProName comp_datums [3];
	ProMatrix identity_matrix = {{ 1.0, 0.0, 0.0, 0.0 }, 
								{0.0, 1.0, 0.0, 0.0}, 
								{0.0, 0.0, 1.0, 0.0}, 
								{0.0, 0.0, 0.0, 1.0}};
	ProAsmcomp asmcomp;
	ProAsmcompconstraint* constraints;
	ProAsmcompconstraint constraint;
	int i;
	ProBoolean interact_flag = PRO_B_FALSE;
	ProModelitem asm_datum, comp_datum;
	ProSelection asm_sel, comp_sel;
	ProAsmcomppath comp_path;
	ProIdTable c_id_table;
	c_id_table [0] = -1;

	/*-----------------------------------------------------------------*\
		Set up the arrays of datum names
    \*-----------------------------------------------------------------*/
	ProStringToWstring (asm_datums [0], "ASM_D_FRONT");
	ProStringToWstring (asm_datums [1], "ASM_D_TOP");
	ProStringToWstring (asm_datums [2], "ASM_D_RIGHT");

	ProStringToWstring (comp_datums [0], "COMP_D_FRONT");
	ProStringToWstring (comp_datums [1], "COMP_D_TOP");
	ProStringToWstring (comp_datums [2], "COMP_D_RIGHT");

	/*-----------------------------------------------------------------*\
		Package the component initially
    \*-----------------------------------------------------------------*/
	ProAsmcompAssemble (asm_model, comp_model, identity_matrix, &asmcomp);

	/*-----------------------------------------------------------------*\
		Prepare the constraints array
    \*-----------------------------------------------------------------*/
	ProArrayAlloc (0, sizeof (ProAsmcompconstraint), 1, (ProArray*)&constraints);

	for (i = 0; i < 3; i++)
	{
		/*-----------------------------------------------------------------*\
			Find the assembly datum 
		\*-----------------------------------------------------------------*/
		status = ProModelitemByNameInit (asm_model, PRO_SURFACE, asm_datums [i], &asm_datum);
		if (status != PRO_TK_NO_ERROR) 
		{
			interact_flag = PRO_B_TRUE;
			continue;
		}
		ProTKPrintf ("Item type = %d, PRO_SURFACE = %d\n", asm_datum.type, PRO_SURFACE);
		fflush (stdout);

		/*-----------------------------------------------------------------*\
			Find the component datum
		\*-----------------------------------------------------------------*/
		status = ProModelitemByNameInit (comp_model, PRO_SURFACE, comp_datums [i], &comp_datum);
		if (status != PRO_TK_NO_ERROR) 
		{
			interact_flag = PRO_B_TRUE;
			continue;
		}
		ProTKPrintf ("Item type = %d, PRO_SURFACE = %d\n", comp_datum.type, PRO_SURFACE);
		fflush (stdout);

		/*-----------------------------------------------------------------*\
			For the assembly reference, initialize a component path.
			This is necessary even if the reference geometry is in the assembly.
		\*-----------------------------------------------------------------*/
		status = ProAsmcomppathInit (asm_model, c_id_table, 0, &comp_path);
		ERROR_CHECK ("ProAsmcomppathInit()", "UserAssembleByDatums", status);

		/*-----------------------------------------------------------------*\
			Allocate the references
		\*-----------------------------------------------------------------*/
		status = ProSelectionAlloc (&comp_path, &asm_datum, &asm_sel);
		status = ProSelectionAlloc (NULL, &comp_datum, &comp_sel);

		/*-----------------------------------------------------------------*\
			Allocate and fill the constraint.
		\*-----------------------------------------------------------------*/
		status = ProAsmcompconstraintAlloc (&constraint);

		status = ProAsmcompconstraintTypeSet (constraint, PRO_ASM_ALIGN);

		status = ProAsmcompconstraintAsmreferenceSet (constraint, asm_sel, PRO_DATUM_SIDE_YELLOW);
			
		status = ProAsmcompconstraintCompreferenceSet (constraint, comp_sel, PRO_DATUM_SIDE_YELLOW);

		status = ProArrayObjectAdd ((ProArray*)&constraints, -1, 1, &constraint);

	}

	/*-----------------------------------------------------------------*\
		Set the assembly component constraints and regenerate the assembly.
    \*-----------------------------------------------------------------*/
	status = ProAsmcompConstraintsSet (NULL, &asmcomp, constraints);
	ERROR_CHECK ("ProAsmcompConstraintsSet()", "UserAssembleByDatums", status);

	ProSolidRegenerate (asmcomp.owner, PRO_REGEN_ALLOW_CONFIRM);

	/*-----------------------------------------------------------------*\
		If any of the expect datums was not found, prompt the user to constrain
		the new component.
    \*-----------------------------------------------------------------*/
	if (interact_flag)
	{
		ProMessageDisplay (MSGFIL, 
			"USER Unable to locate all standard datum references.  New component is packaged.");

		ProAsmcompConstrRedefUI (&asmcomp);
	}

	return (PRO_TK_NO_ERROR);
}

/*=====================================================================*\
FUNCTION: UserAssemble
PURPOSE:  Menu action to assemble a component
\*=====================================================================*/
ProError UserAssemble ()
{
	ProAssembly top_level_asm;
	ProSolid comp_model;
	ProError status;

	ProMdlCurrentGet ((ProMdl*)&top_level_asm);

	status = UserOpenComponent (&comp_model);
	if (status != PRO_TK_NO_ERROR)
		return status;

	UserAssembleByDatums (top_level_asm, comp_model);

	ProWindowRepaint (-1);

	ProTreetoolRefresh (top_level_asm);

	return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UgAssembleByIntent
PURPOSE:  Set constraints after assembling a component using intents
\*=====================================================================*/
ProError UgAssembleByIntent (ProAssembly asm_model, ProSolid comp_model)
{
  ProError status;
  ProMatrix identity_matrix = {{ 1.0, 0.0, 0.0, 0.0 }, 
                               {0.0, 1.0, 0.0, 0.0}, 
                               {0.0, 0.0, 1.0, 0.0}, 
                               {0.0, 0.0, 0.0, 1.0}};
  ProAsmcomp asmcomp;
  ProAsmcompconstraint* constraints;
  ProAsmcompconstraint constraint;

  /*-----------------------------------------------------------------*\
      Package the component initially
  \*-----------------------------------------------------------------*/
  status = ProAsmcompAssemble (asm_model, comp_model, 
                               identity_matrix, &asmcomp);
    
  /*-----------------------------------------------------------------*\
      Prepare the constraints array
  \*-----------------------------------------------------------------*/
  status = ProArrayAlloc (0, sizeof (ProAsmcompconstraint), 1,
                          (ProArray*)&constraints);
    
   /*-----------------------------------------------------------------*\
      Set PRO_LOG_PNT constraint in assembly
  \*-----------------------------------------------------------------*/
  status = UgSelectAsmIntent(asm_model, comp_model, PRO_LOG_PNT,
                             &constraints);   
  
  /*-----------------------------------------------------------------*\
      Set PRO_LOG_PLANE constraint in assembly
  \*-----------------------------------------------------------------*/
  status = UgSelectAsmIntent(asm_model, comp_model, PRO_LOG_PLANE,
                             &constraints);

  /*-----------------------------------------------------------------*\
      Set the assembly component constraints and regenerate the assembly.
  \*-----------------------------------------------------------------*/
  status = ProAsmcompConstraintsSet (NULL, &asmcomp, constraints);
  
  if(status == PRO_TK_NO_ERROR)
    ProMessageDisplay (MSGFIL,"Component assembled successfully");
    
  else 
    return status;
 
  ProSolidRegenerate(asmcomp.owner, PRO_REGEN_ALLOW_CONFIRM);
    
  return (PRO_TK_NO_ERROR);
}

/*=====================================================================*\
FUNCTION: UgSelectAsmIntent
PURPOSE:  Assemble a component using intent point and intent plane
\*=====================================================================*/
ProError UgSelectAsmIntent(ProAssembly asm_model, ProSolid comp_model, 
                           ProType constr_type, 
                           ProAsmcompconstraint** constraints)
{
  ProError status;
  ProAsmcompconstraint constraint;
  int i, n_sels;
  int asm_point,asm_plane,comp_point,comp_plane;
  int constr_point,constr_plane;
  ProModelitem asm_datum, comp_datum;
  ProSelection asm_sel, comp_sel;
  ProAsmcomppath comp_path;
  ProSelection* sels = NULL, *sels2 = NULL;
  ProMdlName selmdl_name, compmdl_name;
  char c_selmdl_name[PRO_MDLNAME_SIZE], c_compmdl_name[PRO_MDLNAME_SIZE];
  ProModelitem p_asmintent, p_compintent;

  /*-----------------------------------------------------------------*\
     Get the intent datum point for the component
  \*-----------------------------------------------------------------*/
  while (1)
  {
    /*-----------------------------------------------------------------*\
        Find the component intent 
    \*-----------------------------------------------------------------*/
    if(constr_type == PRO_LOG_PNT )
      ProMessageDisplay (MSGFIL,"Select the intent point in component");
 
    else if(constr_type == PRO_LOG_PLANE)
      ProMessageDisplay (MSGFIL,"Select the intent plane in component");

    status = ProSelect ("membfeat", 1, NULL, NULL, NULL, NULL, &sels, &n_sels);
    if ((status != PRO_TK_NO_ERROR) || (n_sels < 1))
      return status;

    status = ProSelectionModelitemGet (sels[0], &comp_datum);
    if ((status != PRO_TK_NO_ERROR) || (comp_datum.type != PRO_FEATURE))
      return status;

    status = ProMdlMdlnameGet(comp_datum.owner, selmdl_name);
    ProWstringToString (c_selmdl_name, selmdl_name);
        
    status = ProMdlMdlnameGet(comp_model, compmdl_name);
    ProWstringToString (c_compmdl_name, compmdl_name);

    if(strcmp(c_compmdl_name,c_selmdl_name) != 0)
      continue;

    status = ProModelitemInit(comp_datum.owner,(comp_datum.id+1),constr_type,
                              &p_compintent);
    if (status == PRO_TK_NO_ERROR) 
      break;
  }
    
    
  while(1)
  {
    /*-----------------------------------------------------------------*\
        Find the assembly intent 
    \*-----------------------------------------------------------------*/

    if(constr_type == PRO_LOG_PNT )
      ProMessageDisplay (MSGFIL,"Select the intent point in assembly");
 
    else if(constr_type == PRO_LOG_PLANE)
      ProMessageDisplay (MSGFIL,"Select the intent plane in assembly");

    status = ProSelect ("membfeat", 1, NULL, NULL, NULL, NULL, &sels2, 
                        &n_sels);
    if ((status != PRO_TK_NO_ERROR) || (n_sels < 1))
      return status;

    status = ProSelectionModelitemGet (sels2[0], &asm_datum);
    if ((status != PRO_TK_NO_ERROR)|| (asm_datum.type != PRO_FEATURE))
      return status;

    status = ProSelectionAsmcomppathGet(sels2[0], &comp_path); 
    if (status != PRO_TK_NO_ERROR)
      continue;
          
    status = ProModelitemInit(asm_datum.owner,(asm_datum.id+1),constr_type,
                              &p_asmintent);
    if (status == PRO_TK_NO_ERROR)
      break;    
  }

  /*-----------------------------------------------------------------*\
      Allocate the references
  \*-----------------------------------------------------------------*/
  status = ProSelectionAlloc (&comp_path, &p_asmintent, &asm_sel);
  status = ProSelectionAlloc (NULL, &p_compintent, &comp_sel);

  /*-----------------------------------------------------------------*\
      Allocate and fill the constraint.
  \*-----------------------------------------------------------------*/
  status = ProAsmcompconstraintAlloc (&constraint);
  if(constr_type == PRO_LOG_PNT)
    ProAsmcompconstraintTypeSet (constraint, PRO_ASM_ALIGN);

  else if(constr_type == PRO_LOG_PLANE)
    ProAsmcompconstraintTypeSet (constraint, PRO_ASM_ORIENT);

  status = ProAsmcompconstraintAsmreferenceSet (constraint, asm_sel, 
                                                PRO_DATUM_SIDE_YELLOW);
  status = ProAsmcompconstraintCompreferenceSet (constraint, comp_sel, 
                                                 PRO_DATUM_SIDE_YELLOW);
  status = ProArrayObjectAdd ((ProArray*)constraints, -1, 1, &constraint);

  return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UgAssembleIntent
PURPOSE:  Menu action to assemble a component using intent feature
\*=====================================================================*/
ProError UgAssembleIntent ()
{
  ProAssembly top_level_asm = NULL;
  ProSolid comp_model = NULL;
  ProError status;

  status = ProMdlCurrentGet ((ProMdl*)&top_level_asm);
  if((status != PRO_TK_NO_ERROR) || (top_level_asm == NULL))
  {
    ProMessageDisplay (MSGFIL, "Failed to open the assembly");
    return status;
  }

  status = UserOpenComponent (&comp_model);
  if ((status != PRO_TK_NO_ERROR) || comp_model == NULL ) 
  {
    ProMessageDisplay (MSGFIL, "Failed to open the component");
    return status;
  }
    
  if(top_level_asm && comp_model)
    status = UgAssembleByIntent (top_level_asm, comp_model);

  ProWindowRepaint (-1);

  ProTreetoolRefresh (top_level_asm);

  return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UserOpenComponent
PURPOSE:  Prompt the user to select a component.
\*=====================================================================*/
ProError UserOpenComponent (ProSolid* solid)
{
	ProSolid comp;
    ProError err, er1;
    int version, win_id,sel_n, Oldwin_id;
    ProCharLine line, str;
    ProLine buff;
    ProPath *path_arr, sel_path, def_path, cur_path;
    ProName *path_lab_arr;
	ProMdlName w_name;
	ProMdlExtension w_type;
	ProType type;
    
    ProMessageDisplay(MSGFIL, "USER Choose new component to assemble:");

    /*-----------------------------------------------------------------*\
		Prompt the user to select the file.
    \*-----------------------------------------------------------------*/
	ProStringToWstring(buff, "*.prt,*.asm");
    ProStringToWstring(def_path, ".");

    err = ProArrayAlloc(0, sizeof(ProPath), 1, (ProArray*)&path_arr);
   
    err = ProArrayAlloc(0, sizeof(ProPath), 1, (ProArray*)&path_lab_arr);
   
    err = ProFileMdlnameOpen(NULL, buff, path_arr, path_lab_arr, def_path, NULL,
        sel_path);
  
    if (err == PRO_TK_NO_ERROR)
    {
		/*-----------------------------------------------------------------*\
			Parse the filename to locate the component model.
		\*-----------------------------------------------------------------*/
        err = ProFileMdlnameParse(sel_path, def_path, w_name, w_type, &version);
        
        ProUtilWstrcpy(sel_path, def_path);
        err = ProPathMdlnameCreate(NULL, w_name, w_type, PRO_VALUE_UNUSED, def_path);
       
        ProWstringToString(str, def_path);
        if( ProUtilConfirmNameType(str, line, &type) != PRO_TK_BAD_INPUTS)
        {
			/*-----------------------------------------------------------------*\
				Load the component model.
			\*-----------------------------------------------------------------*/
            err = ProDirectoryCurrentGet(cur_path); 
       
            err = ProDirectoryChange(sel_path); 
      
            err = ProMdlnameRetrieve(w_name, (ProMdlfileType)type, (ProMdl*)&comp);
          
           er1 = ProDirectoryChange(cur_path); 
           
            if (err != PRO_TK_NO_ERROR)
			{
                ProMessageDisplay (MSGFIL, "USER Failed to retrieve %0s", str);
			}
        }
    }
	/*------------------------------------------------------------------*\
		Free allocated memory
	\*--------------------------------------------------------------------*/
    er1 = ProArrayFree((ProArray*)&path_arr);
  
    er1 = ProArrayFree((ProArray*)&path_lab_arr);
   
    if (err != PRO_TK_NO_ERROR)
        return (PRO_TK_BAD_CONTEXT);

	*solid = comp;

	return PRO_TK_NO_ERROR;
}



/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsHighlight
PURPOSE:  Highlights and labels a component's constraints
\*=====================================================================*/
ProError  UserAsmcompConstraintsHighlight (ProAsmcomp* asmcomp)
{
	ProError status, aref_status, cref_status;
	ProSelection comp_constr, asm_constr;
	ProDatumside dtmside;
	ProAsmcompconstraint* constr_array;
	int size, i, i_count;	
	double offset;
	char offset_str [20];
	ProLine entry;
	char type_str [20];
	ProAsmcompConstrType type;

	/*-----------------------------------------------------------------*\
		Get the constraints for the component.
    \*-----------------------------------------------------------------*/
	status = ProAsmcompConstraintsWithComppathGet(asmcomp, NULL, &constr_array);
	if (status != PRO_TK_NO_ERROR)
		return PRO_TK_E_NOT_FOUND;

	ProArraySizeGet (constr_array, &size);

	for (i = 0; i < size; i++)
	{
		/*-----------------------------------------------------------------*\
			Highlight the assembly reference geometry
        \*----------------------------------------------------------------*/
		aref_status = ProAsmcompconstraintAsmreferenceGet (constr_array [i], &asm_constr, &dtmside);

		if (aref_status == PRO_TK_NO_ERROR)
		{
			ProSelectionHighlight (asm_constr, PRO_COLOR_ERROR);

		}

		/*-----------------------------------------------------------------*\
			Highlight the component reference geometry
		\*-----------------------------------------------------------------*/
		cref_status = ProAsmcompconstraintCompreferenceGet (constr_array [i], &comp_constr, &dtmside);

		if (cref_status == PRO_TK_NO_ERROR)
		{
			ProSelectionHighlight (comp_constr, PRO_COLOR_WARNING);
		}

		/*-----------------------------------------------------------------*\
			Prepare and display the message text.
		\*----------------------------------------------------------------*/
		status = ProAsmcompconstraintOffsetGet (constr_array [i], &offset);

		if (status == PRO_TK_NO_ERROR)
		{
			ProTKSprintf (offset_str, " offset = %6.3lf", offset);
		}
		else
			strcpy (offset_str, "");

		status = ProAsmcompconstraintTypeGet (constr_array [i], &type);
		UserConstraintTypeToString (type, type_str);
	
		i_count = i + 1;
		ProMessageDisplay (MSGFIL, "USER Showing constraint %0d of %1d %2s%3s.  Hit <CR> to continue.",
							&i_count, &size, type_str, offset_str);
		ProMessageStringRead (1, entry);

/*-----------------------------------------------------------------*\
	     Clean up the UI for the next constraint
\*-----------------------------------------------------------------*/
		if (aref_status == PRO_TK_NO_ERROR)
		{
			ProSelectionUnhighlight (asm_constr);
		}

		if (cref_status == PRO_TK_NO_ERROR)
		{
			ProSelectionUnhighlight (comp_constr);
		}
	}

	ProArrayFree ((ProArray*)&constr_array);

       return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsInfo
PURPOSE:  Menu action for constraint information gathering
\*=====================================================================*/
ProError UserAsmcompConstraintsInfo ()
{
	ProError status;
	ProSelection* component_arr;
	int size;
	ProAsmcomp cfeat;

	ProMessageDisplay (MSGFIL, "USER Select an assembly component:");
	status = ProSelect ("membfeat", 1, NULL, NULL, NULL, NULL, &component_arr, &size);
	if (status != PRO_TK_NO_ERROR)
		return status;

	ProSelectionModelitemGet (component_arr [0], (ProModelitem*)&cfeat);

	ProSelectionUnhighlight (component_arr [0]);

	ProWindowRepaint (-1);

	UserAsmcompConstraintsHighlight (&cfeat);

	return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UserConstraintTypeToString
PURPOSE:  Utility: convert the constraint type to a string for printing
\*=====================================================================*/
void UserConstraintTypeToString (ProAsmcompConstrType type, 
								  char* type_string)
{

	switch (type)
	{
		case   PRO_ASM_MATE:
			strcpy (type_string, "(Mate)");
			break;
		case PRO_ASM_MATE_OFF:
			strcpy (type_string, "(Mate Offset)");
			break;
		case PRO_ASM_ALIGN:
			strcpy (type_string, "(Align)");
			break;
		case PRO_ASM_ALIGN_OFF:
			strcpy (type_string, "(Align Offset)");
			break;
		case PRO_ASM_INSERT:
			strcpy (type_string, "(Insert)");
			break;
		case PRO_ASM_ORIENT:			
			strcpy (type_string, "(Orient)");
			break;
		case PRO_ASM_CSYS:			
			strcpy (type_string, "(Csys)");
			break;
		case PRO_ASM_TANGENT:			
			strcpy (type_string, "(Tangent)");
			break;
		case PRO_ASM_PNT_ON_SRF:			
			strcpy (type_string, "(Point on Surf)");
			break;
		case PRO_ASM_EDGE_ON_SRF:			
			strcpy (type_string, "(Edge on Surf)");
			break;
		case PRO_ASM_DEF_PLACEMENT:			
			strcpy (type_string, "(Default)");
			break;
		case PRO_ASM_SUBSTITUTE:			
			strcpy (type_string, "(Substitute)");
			break;
		case PRO_ASM_PNT_ON_LINE:			
			strcpy (type_string, "(Point on Line)");
			break;
		case PRO_ASM_FIX:			
			strcpy (type_string, "(Fix)");
			break;
		case PRO_ASM_AUTO:			
			strcpy (type_string, "(Auto)");
			break;
		default:
			strcpy (type_string, "(Unrecognized Type)");
			break;
	}
}

/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsHighlight_OA
PURPOSE:  Object/Action style command for highlight assembly component 
           constraints
\*=====================================================================*/
int UserAsmcompConstraintsHighlight_OA()
{
  ProError status;
  ProSelection* sels;
  ProAsmcomp asmcomp;

/*-----------------------------------------------------------------*\
  Extract the current selected objects from the selection buffer.
  Because the access functions check the type and number, we 
  assume that the correctly selected object (a component feature, or
  part/assembly within the parent assembly) are available.
\*-----------------------------------------------------------------*/
  status = ProSelbufferSelectionsGet (&sels);
  
  status = ProSelectionModelitemGet (sels[0], &asmcomp);
  
/*-----------------------------------------------------------------*\
  If its a selected part or assembly, contstruct the feature handle 
  using the parent assembly and the component id from the component 
  path.
\*-----------------------------------------------------------------*/
  if (asmcomp.type == PRO_PART || asmcomp.type == PRO_ASSEMBLY)
    {
      ProAsmcomppath path;
      ProMdl asmcomp_owner;
      
      status = ProSelectionAsmcomppathGet (sels [0], &path);

      asmcomp.type = PRO_FEATURE;
      asmcomp.id = path.comp_id_table [path.table_num - 1];
      
      path.table_num --;

      status = ProAsmcomppathMdlGet (&path, &asmcomp.owner);      
    }

/*-----------------------------------------------------------------*\
  Call the existing function for highlighting constraints.
\*-----------------------------------------------------------------*/
  UserAsmcompConstraintsHighlight (&asmcomp);

  ProSelectionarrayFree (sels);

  return PRO_TK_NO_ERROR;
}

#define OA 1  /* Standard OA in the menu system, typically gray out 
		 the button when not usable*/
#define PM 2 /* OA in a popup menu, typically remove the button when 
	         not usable */

/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsHighlight_TestLow
PURPOSE:  Test function for access for constraint highlighting
\*=====================================================================*/
uiCmdAccessState UserAsmcompConstraintsHighlight_TestLow (ProSelection* sels,
							  int mode)
{
  uiCmdAccessState access_result;
  ProBoolean should_free = PRO_B_FALSE;
  ProError status;
  int size;

/*-----------------------------------------------------------------*\
  Set the default return if the button is unusable.
\*-----------------------------------------------------------------*/  
  if (mode == OA)
    access_result = ACCESS_UNAVAILABLE;
  else 
    access_result = ACCESS_REMOVE;

/*-----------------------------------------------------------------*\
  If called without selections, extract the current selections from
  the buffer.
\*-----------------------------------------------------------------*/ 
  if (sels == NULL)
    {   
      status = ProSelbufferSelectionsGet (&sels);
      
      if (status != PRO_TK_NO_ERROR)
	return access_result;

      if (sels == NULL)
	return access_result;

      should_free = PRO_B_TRUE;
    }

/*-----------------------------------------------------------------*\
  This command allows only one selection.
\*-----------------------------------------------------------------*/   
  status = ProArraySizeGet (sels, &size);
  
  if (status != PRO_TK_NO_ERROR)
    return access_result;

  if (size == 1)
    {
      ProAsmcomp asmcomp;

      status = ProSelectionModelitemGet (sels [0], &asmcomp);

/*-----------------------------------------------------------------*\
  If the selected type is feature, its feature type must be component.
\*-----------------------------------------------------------------*/   
      if (asmcomp.type == PRO_FEATURE)
	{
	  ProFeattype ftype;

	  status = ProFeatureTypeGet (&asmcomp, &ftype);
      
	  if (ftype == PRO_FEAT_COMPONENT)
	    {
	      access_result = ACCESS_AVAILABLE;
	    }
	}

/*-----------------------------------------------------------------*\
  If the selected type is part or assembly, it must have a parrent
  assembly to use to construct the component feature handle.
\*-----------------------------------------------------------------*/  
      if (asmcomp.type == PRO_PART || asmcomp.type == PRO_ASSEMBLY)
	{
	  ProAsmcomppath path;
	  
	  status = ProSelectionAsmcomppathGet (sels [0], &path);

	  if (path.table_num > 0)
	    {
	      access_result = ACCESS_AVAILABLE;
	    }
	}
    }

  if (should_free)
    ProSelectionarrayFree (sels);
  
  return access_result;
}

/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsHighlight_TestMdlTree
PURPOSE:  Test function for access for constraint highlighting from model 
          tree RMB popup menu.
\*=====================================================================*/
uiCmdAccessState UserAsmcompConstraintsHighlight_TestMdlTree(uiCmdAccessMode mode)
{
  return UserAsmcompConstraintsHighlight_TestLow (NULL, PM);
}

/*=====================================================================*\
FUNCTION: UserAsmcompConstraintsHighlight_TestPM
PURPOSE:  Test function for access for constraint highlighting from
          graphics window RMB popup menu.
\*=====================================================================*/
uiCmdAccessState UserAsmcompConstraintsHighlight_TestPM(uiCmdCmdId id,
                                                        ProAppData data,
							ProSelection* sels)
{
 return UserAsmcompConstraintsHighlight_TestLow (sels, PM);
}

#undef OA
#undef PM