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


/*---------------------- Pro/Toolkit Includes ------------------------*/
#include <ProToolkit.h>
#include <ProSection.h>
#include <ProSecdim.h>
#include <ProSecerror.h>
#include <Pro2dEntdef.h>
#include <ProSecdimType.h>
#include <ProMdl.h>
#include <ProMenu.h>
#include <ProUtil.h>
#include <ProMessage.h>
#include <ProArray.h>
#include <ProElement.h>
#include <ProFeature.h>
#include <TestError.h>
#include <ProSolid.h>


#define MSGFILE L##"msg_ug3dsketch.txt"

ProError UserAddSplineDimension();
ProError UserGetFeatureSection(ProFeature* feat, ProSection *section);
ProError UserCreatePoint (double x, double y, ProSection* section);
ProError UserSetFeatureSection(ProFeature* feat, ProSection *section);


/*================================================================*\
  FUNCTION  : UserAddSplineDimension()
  PURPOSE   : Adds a sectiond dimension to spline entity
\*================================================================*/


ProError UserAddSplineDimension()
{
  
  ProError status;
  wchar_t w_pane_name[PRO_LINE_SIZE];
  ProCharName pane_name;
  ProMdl model;
  ProSelection *sel;
  int num_sel;
  ProFeature sk_feat;
  ProSection feat_section;
  int *int_ids, no_of_ids, i;
  int no_of_points, irange[2];
  int usr_pnt1, usr_pnt2;
  Pro2dEntdef *entity_def;
  Pro2dSplinedef *spline_def;
  Pro2dPointdef *point_def;
  ProBoolean spline_found = PRO_B_FALSE;
  Pro2dPnt pnt1, pnt2, pnt3;
  ProSelection spline_sel, spline_sel2, point_sels[2], point1_sel, point2_sel;
  int ent_ids[2], count = 0;
  ProSelection* sel_array = NULL, *sel_array2 = NULL;  
  int constr_id;
  ProWSecerror  sec_error;
  ProSectionPointType point_types[2];
  Pro2dPnt place_point;
  int sec_dim_id;
    
  status = ProMdlCurrentGet(&model);
  ERROR_CHECK("UserAddSplineDimension","ProMdlCurrentGet",status);
  
  if (status != PRO_TK_NO_ERROR)
    {      
      ProMessageDisplay (MSGFILE, "USER Model does not exist or bad context");
      
      return status;      
    }  
  
  status = ProSelect("feature", 1, NULL, NULL, NULL, NULL, &sel, &num_sel);
  ERROR_CHECK("UserAddSplineDimension","ProSelect",status);
  
  status = ProSelectionModelitemGet(sel[0], (ProModelitem*)&sk_feat);
  ERROR_CHECK("UserAddSplineDimension","ProSelectionModelitemGet",status);
  
  /*================================================================*\
    Access the feature's section pointer from its element tree.
  \*================================================================*/  
    
  status = UserGetFeatureSection(&sk_feat, &feat_section);
  ERROR_CHECK("UserAddSplineDimension","UserGetFeatureSection",status);
    
  if (status != PRO_TK_NO_ERROR)
    return status;
  
  status = ProSectionEntityIdsGet(feat_section, &int_ids, &no_of_ids);
  ERROR_CHECK("UserAddSplineDimension","ProSectionEntityIdsGet",status);
  
  if (status != PRO_TK_NO_ERROR)
    return status;  
  
  /*================================================================*\
     Get the number of interpolation points of the spline entity.
  \*================================================================*/    
    
  for (i=0 ; i<no_of_ids ; i++)
    {
      status = ProSectionEntityGet (feat_section, int_ids[i], &entity_def);
      ERROR_CHECK("UserAddSplineDimension","ProSectionEntityGet",status);      
      
      if (status != PRO_TK_NO_ERROR)
    	return status;      
      
      if(entity_def->type == PRO_2D_SPLINE)
        {
	  spline_found = PRO_B_TRUE;
	  
	  spline_def = (Pro2dSplinedef *)entity_def;
	  no_of_points = spline_def->n_points;
          
          break;
	  
        }
      
      
    }
  
  if (!spline_found)
    {
      status = ProMessageDisplay (MSGFILE, 
      		"USER Feature section does not contain spline"); 
      ERROR_CHECK("UserAddSplineDimension","ProMessageDisplay",status);       
      
      return PRO_TK_E_NOT_FOUND;	
    }
  
  
  status = ProMessageDisplay (MSGFILE, 
		"USER Spline has %0d interpolation points", &no_of_points);
  ERROR_CHECK("UserAddSplineDimension","ProMessageDisplay",status);
  
  /*================================================================*\
     Create a point entity on the first and last interpolation point
     of the spline entity.
  \*================================================================*/    
  
  status = UserCreatePoint (
			    spline_def->point_arr[0][0], 
			    spline_def->point_arr[0][1], 
			    &feat_section);  /* Spline start point */
  ERROR_CHECK("UserAddSplineDimension","ProMdlCurrentGet",status);   
  
  status = UserCreatePoint (
			    spline_def->point_arr[no_of_points-1][0], 
			    spline_def->point_arr[no_of_points-1][1], 
			    &feat_section);  /* Spline end point */  
  ERROR_CHECK("UserAddSplineDimension","UserCreatePoint",status);  
  
  status = ProSectionEntityIdsGet(feat_section, &int_ids, &no_of_ids);
  ERROR_CHECK("UserAddSplineDimension","ProSectionEntityIdsGet",status);  
  
  for (i=0 ; i<no_of_ids ; i++)
    {
      status = ProSectionEntityGet (feat_section, int_ids[i], &entity_def);
      ERROR_CHECK("UserAddSplineDimension","ProSectionEntityGet",status);      
      
      if (status != PRO_TK_NO_ERROR)
        return status;
      
      if(entity_def->type == PRO_2D_SPLINE)
        {        
          spline_def = (Pro2dSplinedef *)entity_def;
          
	  pnt1[0] = spline_def->point_arr[0][0];
	  pnt1[1] = spline_def->point_arr[0][1];
	  
	  pnt2[0] = spline_def->point_arr[no_of_points-1][0];
	  pnt2[1] = spline_def->point_arr[no_of_points-1][1];
	  
	  status = ProSectionEntityGetSelected(feat_section, int_ids[i],
          		 PRO_ENT_START, pnt1, PRO_VALUE_UNUSED, &spline_sel);
          ERROR_CHECK("UserAddSplineDimension",
          	"ProSectionEntityGetSelected",status);   
          
          if (status != PRO_TK_NO_ERROR)
           return status;      
	  
	  status = ProSectionEntityGetSelected(feat_section, int_ids[i],
          		 PRO_ENT_END, pnt2, PRO_VALUE_UNUSED, &spline_sel2);
          ERROR_CHECK("UserAddSplineDimension",
          	"ProSectionEntityGetSelected",status);  
                
          if (status != PRO_TK_NO_ERROR)
           return status;      
	  
        }
      
      if (entity_def->type == PRO_2D_POINT)
        {	                      
	  point_def = (Pro2dPointdef*)entity_def;
	  
	  pnt3[0] = point_def->pnt[0];
	  pnt3[1] = point_def->pnt[1];
	  
	  ent_ids[count] = int_ids[i];
	  
	  status = ProSectionEntityGetSelected(feat_section, int_ids[i],
          		 PRO_ENT_WHOLE, pnt3, PRO_VALUE_UNUSED,
                       	 &(point_sels[count++]));
          ERROR_CHECK("UserAddSplineDimension",
          	"ProSectionEntityGetSelected",status);                         
                
	  if (status != PRO_TK_NO_ERROR)
           return status;                
	  
        }            
      
    }
    
  /*================================================================*\
    Create "Same point" constraint between the point and spline 
    entity at the two locations.
  \*================================================================*/      
  
  status = ProArrayAlloc(0, sizeof(ProSelection), 1, (ProArray*)&sel_array);
  ERROR_CHECK("UserAddSplineDimension","ProArrayAlloc",status);  
  
  status = ProArrayObjectAdd((ProArray*)&sel_array, PRO_VALUE_UNUSED, 1,
  				 &spline_sel);
  ERROR_CHECK("UserAddSplineDimension","ProArrayObjectAdd",status);                                 
  
  status = ProArrayObjectAdd((ProArray*)&sel_array, PRO_VALUE_UNUSED, 1,
  				 &(point_sels[1]));
  ERROR_CHECK("UserAddSplineDimension","ProArrayObjectAdd",status);                                 
  
  status = ProSectionConstraintCreate(feat_section, sel_array, 2,
  				 PRO_CONSTRAINT_SAME_POINT, &constr_id);
  ERROR_CHECK("UserAddSplineDimension","ProSectionConstraintCreate",status);   
  
  if (status != PRO_TK_NO_ERROR)
    return status;                              
  
  status = ProArrayFree((ProArray*)&sel_array);
  ERROR_CHECK("UserAddSplineDimension","ProArrayFree",status);  
  
  status = ProArrayAlloc(0, sizeof(ProSelection), 1, (ProArray*)&sel_array2);
  ERROR_CHECK("UserAddSplineDimension","ProArrayAlloc",status);  
  
  status = ProArrayObjectAdd((ProArray*)&sel_array2, PRO_VALUE_UNUSED, 1,
  				 &spline_sel2);
  ERROR_CHECK("UserAddSplineDimension","ProArrayObjectAdd",status);                                 
  
  status = ProArrayObjectAdd((ProArray*)&sel_array2, PRO_VALUE_UNUSED, 1,
  				 &(point_sels[0]));
  ERROR_CHECK("UserAddSplineDimension","ProArrayObjectAdd",status);                                 
  
  status = ProSectionConstraintCreate(feat_section, sel_array2, 2,
  			 PRO_CONSTRAINT_SAME_POINT, &constr_id);
  ERROR_CHECK("UserAddSplineDimension","ProSectionConstraintCreate",status);
  
  if (status != PRO_TK_NO_ERROR)
    return status;
  
  status = ProArrayFree((ProArray*)&sel_array2);
  ERROR_CHECK("UserAddSplineDimension","ProArrayFree",status);  
  
  status = ProSecerrorAlloc(&sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorAlloc",status);  
  
  status = ProSectionSolve(feat_section, &sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSectionSolve",status);  
  
  status = ProSecerrorFree(&sec_error);      
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorFree",status);  
  
  /*================================================================*\
    Create the section dimension 
  \*================================================================*/    
  
  point_types[0] = PRO_ENT_START;
  point_types[1] = PRO_ENT_END;
  
  /*================================================================*\
    Create the place point with spline's interpolation point
    coordinates to maintain scale for dimension placement.
  \*================================================================*/      
    
  place_point[0] = pnt1[0];
  place_point[1] = pnt2[1];

  status = ProSecdimCreate(feat_section, ent_ids, point_types, 2,
  			 PRO_TK_DIM_PNT_PNT_HORIZ, place_point, &sec_dim_id);
  ERROR_CHECK("UserAddSplineDimension","ProSecdimCreate",status);                         
  
  if (status != PRO_TK_NO_ERROR)
    return status;
  
  status = ProSecerrorAlloc(&sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorAlloc",status);  
  
  status = ProSectionSolve(feat_section, &sec_error);    
  ERROR_CHECK("UserAddSplineDimension","ProSectionSolve",status);  
    
  status = ProSecerrorFree(&sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorFree",status);  
  
  status = ProSecerrorAlloc(&sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorAlloc",status);  
  
  status = ProSectionRegenerate(feat_section, &sec_error);
  ERROR_CHECK("UserAddSplineDimension","ProSectionRegenerate",status);  
  
  status = ProSecerrorFree(&sec_error);  
  ERROR_CHECK("UserAddSplineDimension","ProSecerrorFree",status);  
  
  /*================================================================*\
    Set the modified section pointer back to feature and redefine it.
  \*================================================================*/    
  
  status = UserSetFeatureSection(&sk_feat, &feat_section);
  ERROR_CHECK("UserAddSplineDimension","UserSetFeatureSection",status);  
  
  if (status != PRO_TK_NO_ERROR)
    return status;
  
  status = ProMessageDisplay (MSGFILE, 
      "USER Spline dimension between interpolation points 1 and %0d has been created.", &no_of_points);
  ERROR_CHECK("UserAddSplineDimension","ProMessageDisplay",status);      
  
  
  return status;
}

/*================================================================*\
  FUNCTION  : UserGetFeatureSection()
  PURPOSE   : Retrieve's the feature's section pointer.
\*================================================================*/

ProError UserGetFeatureSection(ProFeature* feat, ProSection *section)
{
  
  ProError status;
  ProElement elem_tree, elem;
  ProElempath elem_path;
  ProValue val;
  ProValueData val_data;
  
  ProElempathItem sketch_path_item[] = {
    {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_STD_SECTION},
    {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_SKETCHER}
  };
  
  status = ProFeatureElemtreeExtract (feat, NULL,
				      PRO_FEAT_EXTRACT_NO_OPTS, &elem_tree );
  ERROR_CHECK("UserGetFeatureSection","ProFeatureElemtreeExtract",status);                                      
  
  status = ProElempathAlloc(&elem_path);
  ERROR_CHECK("UserGetFeatureSection","ProElempathAlloc",status);  
  
  status = ProElempathDataSet(elem_path, sketch_path_item, 2);
  ERROR_CHECK("UserGetFeatureSection","ProElempathDataSet",status);  
  
  status = ProElemtreeElementGet(elem_tree, elem_path, &elem);
  ERROR_CHECK("UserGetFeatureSection","ProElemtreeElementGet",status);  
  
  status= ProElementSpecialvalueGet(elem, NULL, (ProAppData *) section);
  ERROR_CHECK("UserGetFeatureSection"," ProElementSpecialvalueGet ",status);
 
  return status;
  
}

/*================================================================*\
  FUNCTION  : UserCreatePoint()
  PURPOSE   : Creates a section point entity at given coordinates
              in provided section.
\*================================================================*/

ProError UserCreatePoint (double x, double y, ProSection* section)
{
  ProError status;
  Pro2dPointdef point;
  ProWSecerror  sec_error;
  int ent_id = 1;
  
  point.type = PRO_2D_POINT;
  point.pnt[0] = x;
  point.pnt[1] = y;
  
  status = ProSectionEntityAdd(*section,(Pro2dEntdef *)&point, &ent_id);      
  ERROR_CHECK("UserCreatePoint","ProSectionEntityAdd",status);  
  
  return status;
}

/*================================================================*\
  FUNCTION  : UserSetFeatureSection()
  PURPOSE   : Sets the section pointer to given feature and 
              redefine it.
\*================================================================*/

ProError UserSetFeatureSection(ProFeature* feat, ProSection *section)
{
  
  ProError status;
  ProElement elem_tree, elem;
  ProElempath elem_path;
  ProFeatureCreateOptions *opts = 0;
  ProErrorlist err_list;
  
  
  ProElempathItem sketch_path_item[] = {
    {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_STD_SECTION},
    {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_SKETCHER}
  };
  
  status = ProFeatureElemtreeExtract (feat, NULL,
				      PRO_FEAT_EXTRACT_NO_OPTS, &elem_tree );
  ERROR_CHECK("UserSetFeatureSection","ProFeatureElemtreeExtract",status);                                      
  
  status = ProElempathAlloc(&elem_path);
  ERROR_CHECK("UserSetFeatureSection","ProElempathAlloc",status);  
  
  status = ProElempathDataSet(elem_path, sketch_path_item, 2);
  ERROR_CHECK("UserSetFeatureSection","ProElempathDataSet",status);  
  
  status = ProElemtreeElementGet(elem_tree, elem_path, &elem);
  ERROR_CHECK("UserSetFeatureSection","ProElemtreeElementGet",status);  
  
  status = ProElementSpecialvalueSet(elem, (ProAppData)*section);
  ERROR_CHECK("UserSetFeatureSection","ProElementSpecialvalueSet",status);  
  
  status = ProElemtreeElementAdd(elem_tree, elem_path, elem);
  ERROR_CHECK("UserSetFeatureSection","ProElemtreeElementAdd",status);  
  
  status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
    1, (ProArray*)&opts);

  opts[0]= PRO_FEAT_CR_NO_OPTS;

  status = ProFeatureWithoptionsRedefine(NULL, feat, elem_tree,
    opts, PRO_REGEN_NO_FLAGS, &err_list);  
  ERROR_CHECK("UserSetFeatureSection","ProFeatureRedefine",status);  

  status = ProArrayFree((ProArray*)&opts);
  
  return status;
  
}