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


/*--------------------------------------------------------------------*\
Pro/Toolkit includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProMenuBar.h>
#include <ProMdl.h>
#include <ProPart.h>
#include <ProMdlUnits.h>
#include <ProSolid.h>
#include <ProMessage.h>
#include <ProUtil.h>
#include <ProWstring.h>
#include <ProSelbuffer.h>

#include <TestError.h>

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/
static wchar_t  MSGFIL[] = {'u','t','i','l','i','t','i','e','s','.','t','x','t','\0'};

/*=====================================================================*\
FUNCTION: UserPartInfoMass
PURPOSE:  Write a part's mass value & units to the message window.	
\*=====================================================================*/
int UserPartInfoMass (ProPart part)
{
  ProError status;
  double density;
  ProMassProperty massProps;
  ProUnitsystem unitSystem;
  ProUnitsystemType type;
  ProUnititem unit, forceUnit, timeUnit, lengthUnit;
  ProLine massUnitsLabel;

/*--------------------------------------------------------------------*\
Check for the density.  If it hasn't been set, inform the user
\*--------------------------------------------------------------------*/
  status = ProPartDensityGet (part, &density);

  if (status != PRO_TK_NO_ERROR)
    {
      ProMessageDisplay ( MSGFIL, "USER Part has not been assigned density.");
      return PRO_TK_E_NOT_FOUND;
    }

/*--------------------------------------------------------------------*\
Extract the mass properties using the default part coordinate system
\*--------------------------------------------------------------------*/
  status = ProSolidMassPropertyGet (part, NULL, &massProps);

/*--------------------------------------------------------------------*\
Extract system of units
\*--------------------------------------------------------------------*/
  status = ProMdlPrincipalunitsystemGet (part, &unitSystem);

  ProUnitsystemTypeGet (&unitSystem, &type);
  
  if (type == PRO_UNITSYSTEM_MLT)
    {
      ProUnitsystemUnitGet (&unitSystem, PRO_UNITTYPE_MASS, &unit);

      ProWstringCopy (unit.name, massUnitsLabel, PRO_VALUE_UNUSED);
    }
  else
    {
/*--------------------------------------------------------------------*\
If the units are Force/Length/Time, format the units into the correct
equivalent for mass.
\*--------------------------------------------------------------------*/
      ProUnitsystemUnitGet (&unitSystem, PRO_UNITTYPE_FORCE, &forceUnit); 
  
      ProUnitsystemUnitGet (&unitSystem, PRO_UNITTYPE_TIME, &timeUnit);     
   
      ProUnitsystemUnitGet (&unitSystem, PRO_UNITTYPE_LENGTH, &lengthUnit);  
      
      ProMessageToBuffer (massUnitsLabel,
			  MSGFIL, "USER Force unit -> mass", &forceUnit.name, 
			  &timeUnit.name, &lengthUnit.name);
    }

/*--------------------------------------------------------------------*\
Show the mass to the user
\*--------------------------------------------------------------------*/
  ProMessageDisplay ( MSGFIL, "USER Part mass", &massProps.mass, &massUnitsLabel);

  return PRO_TK_NO_ERROR;
}

/*=====================================================================*\
FUNCTION: UserPartInfoMass_AO
PURPOSE:  Action/Object callback for extracting mass from a part.	
\*=====================================================================*/
int UserPartInfoMass_AO()
{
  ProMdl currMdl;
  ProError status;
  
  status = ProMdlCurrentGet (&currMdl);
  ERROR_CHECK ("UserPartInfoMass_AO()",
	       "ProMdlCurrentGet()", status);

  UserPartInfoMass ((ProPart)currMdl);

  return (1);
}

/*=====================================================================*\
FUNCTION: UserPartInfoMass_TestAO
PURPOSE:  Access function for extracting mass from the current part.
\*=====================================================================*/
uiCmdAccessState UserPartInfoMass_TestAO (uiCmdAccessMode mode)
{ 
  ProMdl currMdl;
  ProError status;
  ProMdlType type;
  
  status = ProMdlCurrentGet (&currMdl);
  ERROR_CHECK ("UserPartInfoMass_TestAO()",
	       "ProMdlCurrentGet()", status);
  
  if (status == PRO_TK_NO_ERROR)
    {
      status = ProMdlTypeGet (currMdl, &type);

      if (status == PRO_TK_NO_ERROR && type == PRO_MDL_PART)
	return ACCESS_AVAILABLE;
    }
  return ACCESS_UNAVAILABLE;
}

/*=====================================================================*\
FUNCTION: UserPartInfoMass_OA
PURPOSE:  Object/Action callback for extracting mass from the selected part.
\*=====================================================================*/
int UserPartInfoMass_OA()
{
  ProError status; 
  ProSelection* sel_array;
  ProModelitem item;

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

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

  UserPartInfoMass (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: UserPartInfoMass_TestLow
PURPOSE:  Access function for the button for printing mass info for a part.
\*=====================================================================*/
static uiCmdAccessState UserPartInfoMass_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: UserPartInfoMass_TestMdlTree
PURPOSE:  Access function for the model tree popup menu button.	
\*=====================================================================*/
uiCmdAccessState UserPartInfoMass_TestMdlTree (uiCmdAccessMode mode)
{ 
  return UserPartInfoMass_TestLow (NULL, PM);
}

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

#undef OA
#undef PM