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

/*--------------------------------------------------------------------*\
  Pro/Toolkit includes 
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProMdl.h>
#include <ProGeomitemdata.h>
#include <ProMechanica.h>
#include <ProMechConstraint.h>
#include <ProMechLoad.h>
#include <ProMechMaterialOrient.h>
#include <ProMechMass.h>
#include <ProMechValue.h>
#include <ProModelitem.h>
#include <ProUtil.h>
#include <ProWstring.h>
#include <ProTKRunTime.h>

#include <math.h>
#include <ProMechLoadset.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include <PTMechExamples.h>

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/

static ProError status;

/*=============================================================*\
  FUNCTION: PTMechExGeomReferenceCreate 
  PURPOSE:  This fn is used to get the geom reference. 
\*=============================================================*/

ProError PTMechExGeomReferenceCreate (PTMechExGeomRef* reference , ProMechGeomref *geom_ref)
{
  ProMechGeomref geomref_entity;
  
  status = ProMechgeomrefAlloc (&geomref_entity);
  PT_TEST_LOG_SUCC ("ProMechgeomrefAlloc");

/*--------------------------------------------------------------------*\
Set the geomref type, subtype,id and asmcomppath
\*--------------------------------------------------------------------*/
  
  status = ProMechgeomrefTypeSet (geomref_entity, reference->type);
  PT_TEST_LOG_SUCC ("ProMechgeomrefTypeSet");
  
  if (reference->subtype != PRO_VALUE_UNUSED ) /* Only For Ref.: Curve, Edge, Point, Surface */
    {
      status = ProMechgeomrefSubtypeSet (geomref_entity, reference->subtype);
      PT_TEST_LOG_SUCC ("ProMechgeomrefSubtypeSet");
    }
  
  if (reference->id != PRO_VALUE_UNUSED)  /* For Ref. other than Part */
    {
      status = ProMechgeomrefIdSet (geomref_entity, reference->id);
      PT_TEST_LOG_SUCC ("ProMechgeomrefIdSet");
    }
  
  if ( reference->path != NULL) /* Only For Ref. in Assembly */
    {
      status = ProMechgeomrefPathSet (geomref_entity, reference->path);
      PT_TEST_LOG_SUCC ("ProMechgeomrefPathSet");
    }
  
  *geom_ref = geomref_entity;
  
  return PRO_TK_NO_ERROR;
}

/*=============================================================================*\
  FUNCTION: PTMechExGeomReferenceArrayCreate 
  PURPOSE:This fn creates a ProArray of ProMechGeomref items and outputs the same.
\*=============================================================================*/

ProError PTMechExGeomReferenceArrayCreate (int num_ents, PTMechExGeomRef* array_refs,
        ProMechGeomref **geom_refs)
{
    ProMechGeomref *array_geomrefs;
    int i;

    if ( num_ents == 0 || array_refs == NULL)
        return PRO_TK_BAD_INPUTS;
    else
    {
/*--------------------------------------------------------------------*\
Craeate array of geomref
\*--------------------------------------------------------------------*/
        status = ProArrayAlloc ( num_ents, sizeof (ProMechGeomref), 1,
                (ProArray *) &array_geomrefs);
        PT_TEST_LOG_SUCC ("ProArrayAlloc");
	
        for (i=0; i<num_ents; i++)
	  {
            ProMechGeomref geomref_entity;
	    
            status = PTMechExGeomReferenceCreate ( &array_refs[i], &geomref_entity);
            PT_TEST_LOG_SUCC ("PTMechExGeomReferenceCreate");
	    
            array_geomrefs[i] = geomref_entity;
        }
        *geom_refs = array_geomrefs;
    }

    return PRO_TK_NO_ERROR;
}
/*============================================================================
  FUNCTION: PTMechExGetMechItemByName 
  PURPOSE: This fn is used to get the ProMechItem of a specific ProType
           from the Mechanica UI.
=============================================================================*/

ProError PTMechExGetMechItemByName (ProSolid solid, ProType type, char* item_name, ProMechItem *item)
{
	mechItemData item_data;

    ProAppData data;

	item_data.item_name = item_name;
	item_data.item = item;

/*--------------------------------------------------------------------*\
Visit the solid and collect the names of the items  
\*--------------------------------------------------------------------*/

    status = ProSolidMechitemVisit ( solid, type, MechItem_ActionFn_name , NULL, &item_data);
    PT_TEST_LOG ("ProSolidMechitemVisit", status, (status != PRO_TK_E_FOUND && status != PRO_TK_NO_ERROR));

    if (status == PRO_TK_E_FOUND)
    {
        return PRO_TK_NO_ERROR;
    }
    else
        return PRO_TK_E_NOT_FOUND;

}

/*============================================================================
  FUNCTION: MechItem_ActionFn_name 
  PURPOSE:  Visits the mech item and copies the data of mech item  
=============================================================================*/
ProError MechItem_ActionFn_name (ProMechItem* item, ProError filter_status, ProAppData app_data)
{
	mechItemData *item_data = (mechItemData *)app_data;
    ProName item_wname;
    char item_name[100];

    status = ProMechitemNameGet (item, item_wname);
    PT_TEST_LOG_SUCC ("ProMechitemNameGet");

    ProWstringToString ( item_name, item_wname);

    if (strcmp (item_data->item_name, item_name) == 0)
      {

		item_data->item->id = item->id;
        item_data->item->type = item->type;
        item_data->item->owner = item->owner;
		
		return PRO_TK_E_FOUND;
      }
    
    return PRO_TK_NO_ERROR;
}

/*============================================================================
  FUNCTION: PTMechExMagValueIncrease 
  PURPOSE: Increase the value 5 times  
=============================================================================*/

ProError PTMechExMagValueIncrease(ProLine input_val,ProLine output_val)
{
  double mag;
  char  res[PRO_LINE_SIZE];
  wchar_t w_res[PRO_LINE_SIZE];

  ProWstringToString(res,input_val);

  mag =  (double )atof (res);

  mag = mag * 5;

  ProTKSprintf(res,"%f",mag);
 
  ProStringToWstring(w_res,res);
  ProWstringCopy (w_res,output_val, PRO_VALUE_UNUSED);
  
  return PRO_TK_NO_ERROR;
}

/*============================================================================*\
 FUNCTION: PTMechExConstraintAddinConstraintset 
  PURPOSE: Add Constrint to a Constraintset. 
\*============================================================================*/

ProError PTMechExConstraintAddinConstraintset (ProMdl part, char *constrset_name,
					     ProMechItem *constraint)
{
  
     ProMechItem ui_constraint_item;

     status = PTMechExGetMechItemByName (part, PRO_SIMULATION_CONSTR_SET,constrset_name,
                                       &ui_constraint_item);
     PT_TEST_LOG_SUCC ("PTMechExGetMechItemByName");

     status = ProMechconstrConstrsetAssign ( constraint, ui_constraint_item.id, PRO_B_TRUE);
     PT_TEST_LOG_SUCC ("ProMechconstrConstrsetAssign");

     return status;
}

/*============================================================================*\
 FUNCTION: PTMechExConstraintsetNameGet
 PURPOSE: Get the constrain set name from the mech item 
\*============================================================================*/
ProError PTMechExConstraintsetNameGet (ProMechItem *item, ProCharLine constrset_name) 
{
  ProName item_proname;
  char    item_name [PRO_NAME_SIZE];
  int num_constrset;
  int *array_constrset;

  status = ProMechconstrConstrsetsGet ( item, &array_constrset);
  PT_TEST_LOG_SUCC ("ProMechconstrConstrsetsGet");

  if (status == PRO_TK_NO_ERROR )
  {
      status = ProArraySizeGet (array_constrset, &num_constrset);
      PT_TEST_LOG_SUCC ("ProArraySizeGet");

      if (num_constrset > 0)
      {
          ProMechItem *constrset_item;
          ProName constrset_proname;

          status = PTMechExGetMechItemNameById (item->owner, PRO_SIMULATION_CONSTR_SET, array_constrset[0],
			  constrset_proname);
          PT_TEST_LOG_SUCC ("PTMechExGetMechItemNameById");

          ProWstringToString ( constrset_name, constrset_proname);

       }

  }
  return status;
 }

/*============================================================================*\
FUNCTION:PTMechExGetMechItemNameById
 PURPOSE: Get the mech item from the id
\*============================================================================*/
ProError PTMechExGetMechItemNameById(ProSolid solid, ProType type, int item_id, ProName constrset_proname)
{
	mechItemNameData item_data;

	item_data.item_id = item_id;
	item_data.item_name = constrset_proname;


    status = ProSolidMechitemVisit ( solid, type, MechItem_ActionFn_id , NULL, &item_data);
    PT_TEST_LOG ("ProSolidMechitemVisit", status, (status != PRO_TK_E_FOUND && status != PRO_TK_NO_ERROR));

    if (status == PRO_TK_E_FOUND)
    {
        return PRO_TK_NO_ERROR;
    }
    else
        return PRO_TK_E_NOT_FOUND;

}
/*============================================================================*\
 FUNCTION:MechItem_ActionFn_id
 PURPOSE: Visit the mech item and copy the data
\*============================================================================*/

ProError MechItem_ActionFn_id (ProMechItem* item, ProError filter_status, ProAppData app_data)
{
    int  item_id;
    char item_name[100];

	mechItemNameData *item_data;

	item_data = (mechItemNameData*) app_data;

	item_id = item->id;

    if (item_id == item_data->item_id)
    {
		status = ProMechitemNameGet(item, item_data->item_name);
		PT_TEST_LOG_SUCC ("ProMechitemNameGet");
       return PRO_TK_E_FOUND;
    }

    return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExComponentsVectoredValueCreate 
  PURPOSE  : To Create the vector value for component
\*=============================================================*/
ProError PTMechExComponentsVectoredValueCreate (int n_vector, 
	ProMechExpression exp[], ProMechVectoredValue *vector_val)
{
   ProMechVectoredValue value;
   ProMechDirectionVector dir_vector;
   ProMechValue *arr_val, mech_val;
   int i;
   
   status = ProMechvectoredvalueAlloc (&value);
   PT_TEST_LOG_SUCC ("ProMechvectoredvalueAlloc");
   
   status = ProMechvectoredvalueDirectiontypeSet (value, PRO_MECH_DIRECTION_BY_VECTOR);
   PT_TEST_LOG_SUCC ("ProMechvectoredvalueDirectiontypeSet");  
    
   status = ProMechdirvectorAlloc (&dir_vector);
   PT_TEST_LOG_SUCC ("ProMechdirvectorAlloc");   
   
   status = ProArrayAlloc (3, sizeof (ProMechValue), 1, (ProArray *)&arr_val);
   PT_TEST_LOG_SUCC ("ProArrayAlloc");   
   for (i = 0; i < n_vector; i++)
   {
      status = ProMechvalueAlloc (&mech_val);
      PT_TEST_LOG_SUCC ("ProMechvalueAlloc"); 
      status = ProMechvalueValueSet (mech_val, exp[i]);
      PT_TEST_LOG_SUCC ("ProMechvalueValueSet");
      arr_val[i] = mech_val;      
   }
   status = ProMechdirvectorComponentsSet (dir_vector, arr_val);
   PT_TEST_LOG_SUCC ("ProMechdirvectorComponentsSet");
   
   status = ProMechvectoredvalueDirectionvectorSet (value, dir_vector);
   PT_TEST_LOG_SUCC ("ProMechvectoredvalueDirectionvectorSet");   
   
   *vector_val = value;
   return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExAddLoadinLoadset 
  PURPOSE  : To add created load in specified loadset.
\*=============================================================*/
ProError PTMechExAddLoadinLoadset (ProMdl mdl, char* name, ProMechItem *m_item)
{
   ProMechItem load_item;
   
   status = PTMechExGetMechItemByName ((ProSolid)mdl, PRO_SIMULATION_LOAD_SET, name, &load_item);   
   PT_TEST_LOG_SUCC ("PTMechExGetMechItemByName");
   
   status = ProMechloadLoadsetAssign (m_item, load_item.id, PRO_B_TRUE); 
   PT_TEST_LOG_SUCC ("ProMechloadLoadsetAssign");
    
   return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExValueByExpressionCreate 
  PURPOSE  : To create mech value for load.
\*=============================================================*/
ProError PTMechExValueByExpressionCreate (ProMechExpression exp, ProMechValue *m_value)
{
   ProMechValue m_val;
   
   status = ProMechvalueAlloc (&m_val);
   PT_TEST_LOG_SUCC ("ProMechvalueAlloc");
   
   status = ProMechvalueValueSet (m_val, exp);
   PT_TEST_LOG_SUCC ("ProMechvalueValueSet");
   *m_value = m_val;
   
    return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExDirVectorMagnitudeValueCreate 
  PURPOSE  : To create vector.
\*=============================================================*/
ProError PTMechExDirVectorMagnitudeValueCreate (int data, ProMechExpression mech_exp[], 
					ProMechExpression expr, ProMechVectoredValue *vector)
{
   ProMechVectoredValue v_value;
   ProMechValue mag_val;

   status = PTMechExComponentsVectoredValueCreate (data, mech_exp, &v_value);
   PT_TEST_LOG_SUCC ("PTMechExComponentsVectoredValueCreate");

   status = PTMechExValueByExpressionCreate (expr, &mag_val);
   PT_TEST_LOG_SUCC ("PTMechExValueByExpressionCreate");

   status = ProMechvectoredvalueMagnitudeSet (v_value, mag_val);
   PT_TEST_LOG_SUCC ("ProMechvectoredvalueMagnitudeSet");

   *vector = v_value;
   return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExLoadsetCreate 
  PURPOSE  : To create loadset for load.
\*=============================================================*/
ProError PTMechExLoadsetCreate (ProSolid model, char* loadset_name)
{
   ProMechItem get_item, set_item;
   ProName w_loadset_name;

   ProStringToWstring (w_loadset_name, loadset_name);

   status = PTMechExGetMechItemByName (model, PRO_SIMULATION_LOAD_SET, loadset_name, &get_item);
   PT_TEST_LOG ("PTMechExGetMechItemByName", status, 
   			status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

   if (status == PRO_TK_E_NOT_FOUND)
   {
     status = ProMechitemCreate (model, PRO_SIMULATION_LOAD_SET, &set_item);
     PT_TEST_LOG_SUCC ("ProMechitemCreate");

     status = ProMechitemNameSet (&set_item, w_loadset_name);
     PT_TEST_LOG_SUCC ("ProMechitemNameSet");

     status = ProMechloadsetDescriptionSet (&set_item, L"Loadset for Mechanica Example");
     PT_TEST_LOG_SUCC ("ProMechloadsetDescriptionSet");
   }
   return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  FUNCTION : PTMechExDeleteAndPop 
  PURPOSE  : To delete and pop up the menu.
\*=============================================================*/
ProError PTMechExDeleteAndPop()
{
   status = ProMenuDeleteWithStatus (0);
   PT_TEST_LOG_SUCC ("ProMenuDeleteWithStatus");
   
   status = ProMenuPop();
   PT_TEST_LOG_SUCC ("ProMenuPop");
   
   return PRO_TK_NO_ERROR;
}