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


#include <ProToolkit.h>
#include <ProParameter.h>
#include <ProMaterial.h>
#include <ProUtil.h>
#include <ProSolid.h>
#include <ProMdlUnits.h>

#include <ProSelbuffer.h>
#include <ProUICmd.h>
#include <ProMessage.h>
#include <ProModelitem.h>

#include <TestError.h>

extern int UserPartInfoMass (ProPart part);

/*====================================================================*\
FUNCTION: UserApplyAndUpdateMaterial()
PURPOSE:  Read a material from file, read some of its properties,  and 
          add a user-defined parameter to it.  Then assign it to the model
		  and calculate the model mass properties.
\*====================================================================*/
ProError UserApplyAndUpdateMaterial (ProPart part) 
{
  ProError status;
  ProFileName msg_file;
  ProName fopen_label;
  ProLine filter_string;
  ProPath* shortcut_paths;
  ProName* shortcut_names;
  ProPath mtl_file;
  ProPath mtl_file_path;
  ProPath current_dir;
  ProMdlName mtl_name;
  ProMaterialItem material_item;
  ProParamvalue mtl_type, mtl_density;
  ProUnititem units;
  int mtl_type_value;
  ProParamvalue mtl_prop_value;
  ProName mtl_prop_name;
  ProParameter param;
  ProMaterial material;
  ProPath unit_expression;
  ProMassProperty mass_prop;
  ProUnitsystem unit_system;
  ProUnititem mass_unit;

/*--------------------------------------------------------------------*\
    Set up the message file.
\*--------------------------------------------------------------------*/
  ProStringToWstring (msg_file, "msg_ugparam.txt");

/*--------------------------------------------------------------------*\
    Get the material file name from the user.
\*--------------------------------------------------------------------*/
  ProStringToWstring (fopen_label, "Select material file");
  ProStringToWstring (filter_string, "*.mtl");

  ProArrayAlloc (0, sizeof (ProPath), 1, (ProArray*)&shortcut_paths);
  ProArrayAlloc (0, sizeof (ProName), 1, (ProArray*)&shortcut_names);

  status = ProFileMdlnameOpen (fopen_label, filter_string, shortcut_paths,
			shortcut_names, NULL, NULL, mtl_file);

  ProArrayFree ((ProArray*)&shortcut_paths);
  ProArrayFree ((ProArray*)&shortcut_names);

  if (status != PRO_TK_NO_ERROR) 
    {
      return (status);
    }

/*--------------------------------------------------------------------*\
    Change Pro/ENGINEER to the material file directory
\*--------------------------------------------------------------------*/
  ProFileMdlnameParse (mtl_file, mtl_file_path, mtl_name, NULL, NULL);

  ProDirectoryCurrentGet (current_dir);

  ProDirectoryChange (mtl_file_path);

/*--------------------------------------------------------------------*\
    Read the material from the file.
\*--------------------------------------------------------------------*/
  status = ProMaterialfileRead (part, mtl_name);

  ProDirectoryChange (current_dir);

  if (status != PRO_TK_NO_ERROR)
    {
      ProMessageDisplay (msg_file, "UG MaterialFile Read Error", mtl_name);
      ProDirectoryChange (current_dir);
      return (status);
    }

/*--------------------------------------------------------------------*\
    Get the material type and density.  
\*--------------------------------------------------------------------*/
  status = ProModelitemByNameInit (part, PRO_RP_MATERIAL, mtl_name,
				   &material_item);

  status = ProMaterialPropertyGet (&material_item, PRO_MATPROP_TYPE, 
				   &mtl_type, &units);

  status = ProMaterialPropertyGet (&material_item, PRO_MATPROP_MASS_DENSITY,
				   &mtl_density, &units);

/*--------------------------------------------------------------------*\
    Convert the density units to a user-readable format.
\*--------------------------------------------------------------------*/
  status = ProUnitExpressionGet (&units, unit_expression);

/*--------------------------------------------------------------------*\
    Create a user-defined material property based on the type.
\*--------------------------------------------------------------------*/
  ProStringToWstring (mtl_prop_name, "STRUCTURAL_TYPE");

  mtl_type_value = mtl_type.value.i_val;
	
  mtl_prop_value.type = PRO_PARAM_STRING;
  if (mtl_type_value & PRO_MATERIAL_TYPE_STRUCTURAL_ISOTROPIC)
    {
      ProStringToWstring (mtl_prop_value.value.s_val, "Isotropic");
    }
  else if (mtl_type_value & PRO_MATERIAL_TYPE_STRUCTURAL_ORTHOTROPIC)
    {
      ProStringToWstring (mtl_prop_value.value.s_val, "Orthotropic");
    }
  else
    ProStringToWstring (mtl_prop_value.value.s_val, 
			"Transversely orthotropic");
  ProStringToWstring (mass_unit.name,"in");
  status = ProParameterWithUnitsCreate (&material_item, mtl_prop_name, 
			       &mtl_prop_value,&mass_unit, &param);
								
/*--------------------------------------------------------------------*\
    Assign the material.
\*--------------------------------------------------------------------*/
  material.part = part;
  ProWstringCopy (mtl_name, material.matl_name, PRO_VALUE_UNUSED);

  status = ProMaterialCurrentSet (&material);

  ProMessageDisplay (msg_file, "UG MaterialFile Mass Info", mtl_name,
		     &mtl_density.value.d_val, unit_expression);

/*--------------------------------------------------------------------*\
    Compute and display the mass properties.
\*--------------------------------------------------------------------*/
  UserPartInfoMass (part);

  return (0);
}

/*=====================================================================*\
FUNCTION: UserApplyMaterial_OA
PURPOSE:  Object/Action callback for applying material to the part.
\*=====================================================================*/
int UserApplyMaterial_OA()
{
  ProError status; 
  ProSelection* sel_array;
  ProModelitem item;

/*--------------------------------------------------------------------*\
Extract the current selected part
\*--------------------------------------------------------------------*/
  status = ProSelbufferSelectionsGet (&sel_array);

  status = ProSelectionModelitemGet (sel_array [0], &item);

  UserApplyAndUpdateMaterial (item.owner);

  ProSelectionarrayFree (sel_array);

  return (1);
}

#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: UserApplyMaterial_TestLow
PURPOSE:  Access function for the button for applying material to a part.
\*=====================================================================*/
static uiCmdAccessState UserApplyMaterial_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)
    {
      ProModelitem item;

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

/*-----------------------------------------------------------------*\
  The selected type must be part.
\*-----------------------------------------------------------------*/   
      if (item.type == PRO_PART)
	{
	  access_result = ACCESS_AVAILABLE;	  
	}
    }

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

/*=====================================================================*\
FUNCTION: UserApplyMaterial_TestMdlTree
PURPOSE:  Access function for the model tree popup menu button.	
\*=====================================================================*/
uiCmdAccessState UserApplyMaterial_TestMdlTree (uiCmdAccessMode mode)
{ 
  return UserApplyMaterial_TestLow (NULL, PM);
}

/*=====================================================================*\
FUNCTION: UserApplyMaterial_TestPM
PURPOSE:  Access function for the graphics window popup menu button.	
\*=====================================================================*/
uiCmdAccessState UserApplyMaterial_TestPM (uiCmdCmdId id,
				      ProAppData data,
				      ProSelection* sels)
{ 
  return UserApplyMaterial_TestLow (sels, PM);
}

#undef OA
#undef PM