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


#include <ProToolkitErrors.h>
#include <ProSelection.h>
#include <ProElement.h>
#include <ProMfg.h>
#include <ProMfgOptions.h>
#include <ProUtil.h>
#include <ProTKRunTime.h>

#include <TestError.h>
#include <UtilString.h>
#include <TestConsts.h>
#include <UgMfg.h>



/*====================================================================*\
FUNCTION : UserMfgParamSet
PURPOSE  : Set mfg parameter element 
\*====================================================================*/
ProError UserMfgParamSet( 
/*--------------------------------------------------------------------*/
char			*param_name,
ProValueDataType	data_type,
ProValueData		*in_value_data,
ProMfgParamAttr		param_attr,
ProElement		param_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0, table_size = 0;
 ProName		wparam_name;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MFG_PRM_NAME,     PRO_VALUE_TYPE_WSTRING },
   { PRO_E_MFG_PRM_ATTR,     PRO_VALUE_TYPE_INT     },
   { PRO_E_MFG_PRM_VAL_DBL,  PRO_VALUE_TYPE_DOUBLE  },
   { PRO_E_MFG_PRM_VAL_STR,  PRO_VALUE_TYPE_WSTRING }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 if ( data_type != PRO_VALUE_TYPE_DOUBLE &&
      data_type != PRO_VALUE_TYPE_WSTRING )
 {
   return ( PRO_TK_BAD_INPUTS );
 }

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserMfgParamSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MFG_PRM_NAME:
        ProStringToWstring( wparam_name, param_name );

		err = ProElementWstringSet(element, wparam_name);
			  ERROR_CHECK( "UserMfgParamSet", "ProElementWstringSet()", err );
        break;

     case PRO_E_MFG_PRM_ATTR:
		err = ProElementIntegerSet (element, param_attr);
		ERROR_CHECK( "UserWorkcellCreate","ProElementIntegerSet()", err );
        break;

     case PRO_E_MFG_PRM_VAL_DBL:
        if ( data_type == PRO_VALUE_TYPE_DOUBLE )
		{
			err = ProElementDoubleSet (element, in_value_data->v.d);
			ERROR_CHECK( "UserWorkcellCreate","ProElementDoubleSet()", err );
		}

        else
		{
		  	err = ProElementDoubleSet (element, (double) 0.0);
			ERROR_CHECK( "UserWorkcellCreate","ProElementDoubleSet()", err );
		}
        break;

     case PRO_E_MFG_PRM_VAL_STR:
          if ( data_type == PRO_VALUE_TYPE_WSTRING )
          {
            if ( in_value_data->v.w != NULL )
            {
			  err = ProElementWstringSet(element, in_value_data->v.w);
			  ERROR_CHECK( "UserMfgParamSet", "ProElementWstringSet()", err );
            }
          }		  
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserMfgParamSet","UserMfgParamSet()", err );
        break;
   }

   err = ProElemtreeElementAdd( param_elem, NULL, element );
   ERROR_CHECK( "UserMfgParamSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserMfgParamArrSet
PURPOSE  : Set parameter array element
\*====================================================================*/
ProError UserMfgParamArrSet( 
/*--------------------------------------------------------------------*/
MfgPrmDblValue	dbl_params[],
int		n_dbl_params,
MfgPrmStrValue	str_params[],
int		n_str_params,
ProElement	params_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0;

 /**********************************/
 /* PARAMETERS WITH DOUBLE VALUES  */
 /**********************************/
 for ( ii = 0; ii < n_dbl_params; ii++ )
 {
   err = ProElementAlloc( PRO_E_MFG_PARAM_COMPOUND, &element );
   ERROR_CHECK( "UserMfgParamArrSet", "ProElementAlloc", err );

   value_data.v.d = dbl_params[ii].dbl_val;

   err = UserMfgParamSet( dbl_params[ii].param_name, 
                          PRO_VALUE_TYPE_DOUBLE,
                          &value_data, 
                          PRO_MFG_PRM_ATTR_MODIFIED,
                          element );

   ERROR_CHECK( "UserMfgParamArrSet","UserMfgParamSet", err );

   err = ProElemtreeElementAdd( params_elem, NULL, element );
   ERROR_CHECK( "UserMfgParamArrSet","ProElemtreeElementAdd", err );
 }

 /**********************************/
 /* PARAMETERS WITH STRING VALUES  */
 /**********************************/
 value_data.v.w = (wchar_t*) malloc( sizeof(ProLine) );

 for ( ii = 0; ii < n_str_params; ii++ )
 {
   err = ProElementAlloc( PRO_E_MFG_PARAM_COMPOUND, &element );
   ERROR_CHECK( "UserMfgParamArrSet", "ProElementAlloc", err );

   if ( value_data.v.w != NULL )
   {
     err = ProWstringCopy( str_params[ii].str_val, value_data.v.w,
                           PRO_VALUE_UNUSED );
     ERROR_CHECK( "UserMfgParamArrSet","ProWstringCopy()", err );
   }

   err = UserMfgParamSet( str_params[ii].param_name, 
                          PRO_VALUE_TYPE_WSTRING,
                          &value_data, 
                          PRO_MFG_PRM_ATTR_MODIFIED,
                          element );

   ERROR_CHECK( "UserMfgParamArrSet","UserMfgParamSet", err );

   err = ProElemtreeElementAdd( params_elem, NULL, element );
   ERROR_CHECK( "UserMfgParamArrSet","ProElemtreeElementAdd", err );
 }

 free( value_data.v.w );

 return ( err );
}

/*====================================================================*\
FUNCTION : UserToolCompoundSet
PURPOSE  : Set tool reference element
\*====================================================================*/
ProError UserToolCompoundSet( 
/*--------------------------------------------------------------------*/
int		head_number,
int		pocket_number,
wchar_t		*tool_name,
ProElement	tool_ref_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 int			ii = 0, table_size = 0;
 static ElemTable	elem_table[] = 
 {
   { PRO_E_MFG_TOOL_REF_HEAD_NUM, PRO_VALUE_TYPE_INT     },
   { PRO_E_MFG_TOOL_REF_POCKET,   PRO_VALUE_TYPE_INT     },
   { PRO_E_MFG_TOOL_REF_ID,       PRO_VALUE_TYPE_WSTRING }
 };

 table_size = sizeof( elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserToolCompoundSet","ProElementAlloc()", err );

   switch ( elem_table[ii].elem_type )
   {
     case PRO_E_MFG_TOOL_REF_HEAD_NUM:
		err = ProElementIntegerSet(element, head_number);
		ERROR_CHECK( "UserToolCompoundSet", "ProElementIntegerSet()", err );
        break;

     case PRO_E_MFG_TOOL_REF_POCKET:
		err = ProElementIntegerSet(element, pocket_number);
		ERROR_CHECK( "UserToolCompoundSet", "ProElementIntegerSet()", err );
        break;

     case PRO_E_MFG_TOOL_REF_ID:
		err = ProElementWstringSet(element, tool_name);
		ERROR_CHECK( "UserToolCompoundSet", "ProElementWstringSet()", err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserToolCompoundSet","UserToolCompoundSet()", err );
        break;
   }

   err = ProElemtreeElementAdd( tool_ref_elem, NULL, element );
   ERROR_CHECK( "UserToolCompoundSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
FUNCTION : UserPlaneRetractSet
PURPOSE  : Set retract element for plane retract
\*====================================================================*/
ProError UserPlaneRetractSet( 
/*--------------------------------------------------------------------*/
ProSelection	retract_plane,
ProElement	retract_elem

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value;
 ProSelection		selection;
 ProReference		reference;
 int			ii = 0, table_size = 0;
 static ElemTable	retract_elem_table[] = 
 {
   { PRO_E_RETR_SURF_TYPE,     PRO_VALUE_TYPE_INT       },
   { PRO_E_RETR_SURF_REF,      PRO_VALUE_TYPE_SELECTION }
 };

 table_size = sizeof( retract_elem_table ) / sizeof( ElemTable );

 for ( ii = 0; ii < table_size; ii++ )
 {
   err = ProElementAlloc( retract_elem_table[ii].elem_type, &element );
   ERROR_CHECK( "UserPlaneRetractSet","ProElementAlloc()", err );

   switch ( retract_elem_table[ii].elem_type )
   {
     case PRO_E_RETR_SURF_TYPE:
        break;

     case PRO_E_RETR_SURF_REF:
        selection = retract_plane;
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserPlaneRetractSet","UserPlaneRetractSet()", err );
        break;
   }

   if ( retract_elem_table[ii].val_type != PRO_VALUE_TYPE_SELECTION )
   {



     err = ProElementIntegerSet(element,PRO_RETR_SURF_PLANE);
     ERROR_CHECK( "UserPlaneRetractSet", "ProElementIntegerSet()", err );
   }
   else if ( retract_elem_table[ii].val_type == PRO_VALUE_TYPE_SELECTION )
   {
     err = ProSelectionToReference( selection, &reference );
     ERROR_CHECK( "UserPlaneRetractSet()", "ProSelectionToReference", err );

     err = ProElementReferenceSet( element, reference );
     ERROR_CHECK( "UserPlaneRetractSet()", "ProElementReferenceSet", err );
   }

   err = ProElemtreeElementAdd( retract_elem, NULL, element );
   ERROR_CHECK( "UserPlaneRetractSet","ProElemtreeElementAdd", err );
 }

 return ( err );
}

/*====================================================================*\
Function : UserNcSeqTreeCommonElementsAdd
Purpose  : Add commont nc sequence elements to element tree
             - feature type;
             - sequence type;
             - feature name;
             - sequence type;
             - operation reference;
             - csys reference;
             - tool reference;  
             - mfg parameters;
\*====================================================================*/
ProError UserNcSeqTreeCommonElementsAdd (
/*--------------------------------------------------------------------*/
ProMfg		   mfg_model,
int		   feat_type,
ProNcseqType	   ncseq_type,
ProName		   feat_name,
ProSelection	   operation,
ProSelection	   retract_plane, /* can be NULL for turning sequences */
ProSelection	   seq_csys,
ProMfgToolHeadType head_num,
int		   pocket_num,
wchar_t		   *tool_name,
MfgPrmDblValue     dbl_params[],
int		   n_dbl_params,
MfgPrmStrValue     str_params[],
int		   n_str_params,
ProElement	   elem_tree

)
/*--------------------------------------------------------------------*/
{
 ProError		err = PRO_TK_NO_ERROR;
 ProElement		element;
 ProValueData		value_data;
 ProValue		value = NULL;
 ProSelection		selection;
 ProReference		reference = NULL;
 int            	ii = 0, size = 0;
 static ElemTable	common_elements[] =  
 {
   { PRO_E_FEATURE_TYPE,          PRO_VALUE_TYPE_INT       },
   { PRO_E_STD_FEATURE_NAME,      PRO_VALUE_TYPE_WSTRING   },
   { PRO_E_NCSEQ_TYPE,            PRO_VALUE_TYPE_INT       },
   { PRO_E_MFG_OPER_REF,          PRO_VALUE_TYPE_SELECTION },
   { PRO_E_NCSEQ_CSYS,            PRO_VALUE_TYPE_SELECTION },
   { PRO_E_RETR_SURF,             COMPOUND                 },
   { PRO_E_MFG_TOOL_REF_COMPOUND, COMPOUND                 },
   { PRO_E_MFG_PARAM_ARR,         ARRAY                    }
 };
		
 size = sizeof( common_elements ) / sizeof( ElemTable );

 for ( ii = 0 ; ii < size; ii++ )
 {
   err = ProElementAlloc( common_elements[ii].elem_type, &element );
   ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd","ProElementAlloc()", err );

   switch ( common_elements[ii].elem_type )
   {
     case PRO_E_FEATURE_TYPE :
		err = ProElementIntegerSet( element, feat_type );
		ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd()", 
					"ProElementIntegerSet", err );
        break;

     case PRO_E_STD_FEATURE_NAME:
		err = ProElementWstringSet( element, feat_name );
		ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd()", 
					"ProElementWstringSet", err );
        break;

     case PRO_E_NCSEQ_TYPE :
		err = ProElementIntegerSet( element, ncseq_type );
		ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd()", 
					"ProElementIntegerSet", err );
        break;

     case PRO_E_MFG_OPER_REF :
        selection = operation;
        break;

     case PRO_E_NCSEQ_CSYS:
        selection = seq_csys;
        break;

     case PRO_E_RETR_SURF :
        if ( retract_plane == NULL )  /* allowed for turning sequences */
        {
          err = ProElementFree( &element );
          continue;
        }
        else
        {
          err = UserPlaneRetractSet( retract_plane, element );
          ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd", 
                       "UserPlaneRetractSet()", err );
        }
        break;

     case PRO_E_MFG_TOOL_REF_COMPOUND:
        if ( tool_name == NULL )  /* allowed for manual cycle sequence */
        {
          err = ProElementFree( &element );
          continue;
        }
        else
        {
          err = UserToolCompoundSet( head_num, pocket_num, tool_name, 
                                     element );
          ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd", 
                       "UserToolCompoundSet()", err );
        }
        break;

     case PRO_E_MFG_PARAM_ARR:
        err = UserMfgParamArrSet( dbl_params, n_dbl_params,
                                  str_params, n_str_params,
                                  element );
        ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd", "UserMfgParamArrSet()", 
                     err );
        break;

     default:
        ProTKFprintf( stderr, "Error setting element type\n" );
        err = PRO_TK_GENERAL_ERROR;
        ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd",
                     "UserNcSeqTreeCommonElementsAdd()", err );
        break;
   }
	
   if ( common_elements[ii].val_type == PRO_VALUE_TYPE_SELECTION )
   {
     err = ProSelectionToReference( selection, &reference );
     ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd()", 
                  "ProSelectionToReference", err );

     err = ProElementReferenceSet( element, reference );
     ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd()", 
                  "ProElementReferenceSet", err );
   }

   /*--------------------------------------------------------------------*\
        Add the element to elem tree
   \*--------------------------------------------------------------------*/
   err = ProElemtreeElementAdd( elem_tree, NULL, element );
   ERROR_CHECK( "UserNcSeqTreeCommonElementsAdd", "ProElemtreeElementAdd()", 
                err );
 }

 return ( (int)err );
}