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


/*---------------------- Pro/Toolkit Includes ------------------------*/
#include <ProToolkit.h>
#include <ProMdl.h>
#include <ProElement.h>
#include <ProFeatType.h>
#include <ProFeatForm.h>
#include <ProSweep.h>
#include <ProFeature.h>
#include <ProSection.h>
#include <ProSecdim.h>
 
/*---------------------- Pro/Develop Includes ------------------------*/

/*---------------------- Application Includes ------------------------*/
#include <TestError.h>

/*---------------------- Application Typedefs ------------------------*/
typedef struct element_data
{
    ProElement parent_element;
    ProElemId elem_id;
    ProValueData value_data;
} UgElemdata;

/*---------------------- Prototypes ----------------------------------*/
ProError UgFeatElemAdd(UgElemdata *elem,ProElement *added_elem);
ProError UgFeatElemValueGet(ProElement tree, ProElempathItem *path, int size, 
			    ProValueData *elem_val);
ProError UgSectionRegenerate(ProSection section);
ProError UgSweepSpineSktCreate(ProSection section);
ProError UgSweepSectSktCreate(ProSection section);
ProError UgFeatElemRemove(ProElement tree, ProElempathItem *path, int size);
ProError UgFeatElemAddSecMethod(ProElement std_sec_elem);

/*====================================================================*\
Function: UgBaseSweepProtrCreate
Purpose: Example to demonstrate creation of first feature sweep protrusion
\*====================================================================*/
int UgBaseSweepProtrCreate(ProPart part )
{
    ProError err;
    UgElemdata elem_data;
    ProFeature feature;
    ProErrorlist ftcr_errs;
    ProElement elem,elem_tree;
    ProSelection part_sel;
    ProModelitem part_mdlitem;
    ProFeatureCreateOptions *ftcropts = 0;
    ProElempathItem sect_path[] = {{PRO_ELEM_PATH_ITEM_TYPE_ID,
				    PRO_E_SWEEP_SECTION}};
    ProElempathItem spine_skt_path[] = {{PRO_ELEM_PATH_ITEM_TYPE_ID,
					 PRO_E_SWEEP_SPINE},
                                        {PRO_ELEM_PATH_ITEM_TYPE_ID,
					 PRO_E_SKETCHER}};
    ProElempathItem sect_skt_path[] = {{PRO_ELEM_PATH_ITEM_TYPE_ID,
					 PRO_E_SWEEP_SECTION},
                                        {PRO_ELEM_PATH_ITEM_TYPE_ID,
					 PRO_E_SKETCHER}};
    ProValueData spine_skt_val, sect_skt_val;

    if (part == NULL)
    {
	err = ProMdlCurrentGet((ProMdl *)&part);
	ERROR_CHECK("ProMdlCurrentGet","UgBaseSweepProtrCreate",err);
    }
/*--------------------------------------------------------------------*\
Initialize element tree
\*--------------------------------------------------------------------*/
    err = ProElementAlloc(PRO_E_FEATURE_TREE,&elem_tree);
    ERROR_CHECK("ProElementAlloc","UgBaseSweepProtrCreate",err);

/*--------------------------------------------------------------------*\
Add feature type element to the tree
\*--------------------------------------------------------------------*/
    elem_data.parent_element = elem_tree;
    elem_data.elem_id = PRO_E_FEATURE_TYPE;
    elem_data.value_data.type = PRO_VALUE_TYPE_INT;
    elem_data.value_data.v.i = PRO_FEAT_FIRST_FEAT;
    err = UgFeatElemAdd(&elem_data,&elem);
       
/*--------------------------------------------------------------------*\
Add feature form element to the tree
\*--------------------------------------------------------------------*/
    elem_data.parent_element = elem_tree;
    elem_data.elem_id = PRO_E_FEATURE_FORM;
    elem_data.value_data.type = PRO_VALUE_TYPE_INT;
    elem_data.value_data.v.i = PRO_SWEEP;
    err = UgFeatElemAdd(&elem_data,&elem);

/*--------------------------------------------------------------------*\
Add section method for the spine section 
\*--------------------------------------------------------------------*/
    elem_data.parent_element = elem_tree;
    elem_data.elem_id = PRO_E_SWEEP_SPINE;
    elem_data.value_data.type = -1;
    elem_data.value_data.v.i = 0;
    err = UgFeatElemAdd(&elem_data,&elem);
    err = UgFeatElemAddSecMethod(elem);

/*--------------------------------------------------------------------*\
Add section method for the sweep section 
\*--------------------------------------------------------------------*/
    elem_data.parent_element = elem_tree;
    elem_data.elem_id = PRO_E_SWEEP_SECTION;
    elem_data.value_data.type = -1;
    elem_data.value_data.v.i = 0;
    err = UgFeatElemAdd(&elem_data,&elem);
    err = UgFeatElemAddSecMethod(elem);

/*--------------------------------------------------------------------*\
Create incomplete feature to initialize spine sketch handle
\*--------------------------------------------------------------------*/
    err = ProMdlToModelitem((ProMdl)part,&part_mdlitem);
    ERROR_CHECK("ProMdlToModelitem","UgBaseSweepProtrCreate",err);
    err = ProSelectionAlloc(NULL,&part_mdlitem,&part_sel);
    ERROR_CHECK("ProSelectionAlloc","UgBaseSweepProtrCreate",err);
    status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
        1, (ProArray*)&ftcropts);

    ftcropts[0]= PRO_FEAT_CR_INCOMPLETE_FEAT;

    err = ProFeatureWithoptionsCreate(part_sel,elem_tree,
        ftcropts, PRO_REGEN_NO_FLAGS,&feature, &ftcr_errs);
    ERROR_CHECK("ProFeatureWithoptionsCreate","UgBaseSweepProtrCreate",err);

    err = ProElementFree(&elem_tree);
    ERROR_CHECK("ProElementFree","UgBaseSweepProtrCreate",err);

/*--------------------------------------------------------------------*\
Retrieve initialized element tree from the proe data base
\*--------------------------------------------------------------------*/
  err = ProFeatureElemtreeExtract (&feature,NULL,PRO_FEAT_EXTRACT_NO_OPTS,&elem_tree);
  ERROR_CHECK ("ProFeatureElemtreeExtract()","UgBaseSweepProtrCreate",err);

/*--------------------------------------------------------------------*\
Get the spine sketch handle from the element tree
\*--------------------------------------------------------------------*/
    err = UgFeatElemValueGet(elem_tree,spine_skt_path,2,&spine_skt_val);

/*--------------------------------------------------------------------*\
Create sweep spine
\*--------------------------------------------------------------------*/
    err = UgSweepSpineSktCreate((ProSection)spine_skt_val.v.p);

/*--------------------------------------------------------------------*\
Remove sweep section element tree to avoid unitialized data 
\*--------------------------------------------------------------------*/
    err = UgFeatElemRemove(elem_tree,sect_path,1);

/*--------------------------------------------------------------------*\
Add section method for the sweep x-section 
\*--------------------------------------------------------------------*/
    elem_data.parent_element = elem_tree;
    elem_data.elem_id = PRO_E_SWEEP_SECTION;
    elem_data.value_data.type = -1;
    elem_data.value_data.v.i = 0;
    err = UgFeatElemAdd(&elem_data,&elem);
    err = UgFeatElemAddSecMethod(elem);

/*--------------------------------------------------------------------*\
Redefine feature as incomplete to add spine and initialize section sketch
\*--------------------------------------------------------------------*/
    err = ProFeatureWithoptionsRedefine(NULL,&feature,elem_tree,
        ftcropts, PRO_REGEN_NO_FLAGS, &ftcr_errs);
    ERROR_CHECK("ProFeatureWithoptionsRedefine","UgBaseSweepProtrCreate",err);

    status = ProArrayFree((ProArray*)&ftcropts);
    err = ProFeatureElemtreeFree(&feature, elem_tree);
    ERROR_CHECK("ProFeatureElemtreeFree","UgBaseSweepProtrCreate",err);

/*--------------------------------------------------------------------*\
Retrieve initialized element tree from the proe data base
\*--------------------------------------------------------------------*/
  err = ProFeatureElemtreeExtract (&feature, NULL, PRO_FEAT_EXTRACT_NO_OPTS,
		&elem_tree);
  ERROR_CHECK ("ProFeatureElemtreeExtract","UgBaseSweepProtrCreate",err);

/*--------------------------------------------------------------------*\
Get the section sketch handle from the element tree
\*--------------------------------------------------------------------*/
    err = UgFeatElemValueGet(elem_tree,sect_skt_path,2,&sect_skt_val);

/*--------------------------------------------------------------------*\
Create sweep section sketch
\*--------------------------------------------------------------------*/
    err = UgSweepSectSktCreate((ProSection)sect_skt_val.v.p);

/*--------------------------------------------------------------------*\
Redefine feature to create complete feature
\*--------------------------------------------------------------------*/

    status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
        1, (ProArray*)&ftcropts);

    ftcropts[0]= PRO_FEAT_CR_NO_OPTS;

    err = ProFeatureWithoptionsRedefine(NULL,&feature,elem_tree,
        ftcropts, PRO_REGEN_NO_FLAGS, &ftcr_errs);
    ERROR_CHECK("ProFeatureWithoptionsRedefine","UgBaseSweepProtrCreate",err);

    status = ProArrayFree((ProArray*)&ftcropts);
    err = ProFeatureElemtreeFree(&feature, elem_tree);
    ERROR_CHECK("ProFeatureElemtreeFree","UgBaseSweepProtrCreate",err);

    return(err);
}
/*====================================================================*\
Function: UgFeatElemAdd
Purpose: Adds a generic feature element to the element tree
\*====================================================================*/
ProError UgFeatElemAdd(UgElemdata *elem,ProElement *added_elem)
{
    ProValue value;
    ProElement element;
    ProError err;


    err = ProElementAlloc(elem->elem_id,&element);
    ERROR_CHECK("ProElementAlloc","UgFeatElemAdd",err);
    
    if (elem->value_data.type == PRO_VALUE_TYPE_INT)
    {	
	    err = ProElementIntegerSet (element, elem->value_data.v.i);
    	ERROR_CHECK("ProElementValueSet"," ProElementIntegerSet",err);
    }

    err = ProElemtreeElementAdd(elem->parent_element,NULL,element);
    ERROR_CHECK("ProElemtreeElementAdd","UgFeatElemAdd",err);
    
    *added_elem = element;
    
    return(err);
}
/*====================================================================*\
Function: UgFeatElemAddSecMethod
Purpose: adds necessary elements below PRO_E_STD_SECTION elem to 
	 specify sec method element
\*====================================================================*/
ProError UgFeatElemAddSecMethod(ProElement std_sec_elem)
{
    ProElement elem;
    UgElemdata elem_data;
    ProError err;

    elem_data.parent_element = std_sec_elem;
    elem_data.elem_id = PRO_E_STD_SEC_SETUP;
    elem_data.value_data.type = -1;
    elem_data.value_data.v.i = 0;
    err = UgFeatElemAdd(&elem_data,&elem);

    elem_data.parent_element = elem;
    elem_data.elem_id = PRO_E_STD_SEC_METHOD;
    elem_data.value_data.type = PRO_VALUE_TYPE_INT;
    elem_data.value_data.v.i = PRO_SEC_SKETCH;
    err = UgFeatElemAdd(&elem_data,&elem);

    return(0);
}
/*====================================================================*\
Function: UgFeatElemValueGet
Purpose: Gets a feature element from the element tree
\*====================================================================*/
ProError UgFeatElemValueGet(ProElement tree, ProElempathItem *path, int size, 
			    ProValueData *elem_val)
{
    ProElempath elem_path;
    ProElement elem;
    ProValue value;
    ProError err;

    err = ProElempathAlloc(&elem_path);
    ERROR_CHECK("ProElempathAlloc","UgFeatElemGet",err);

    err = ProElempathDataSet(elem_path,path,size);
    ERROR_CHECK("ProElempathDataSet","UgFeatElemGet",err);

    err = ProElemtreeElementGet(tree,elem_path,&elem);
    ERROR_CHECK("ProElemtreeElementGet","UgFeatElemValueGet",err);

	err = ProElementSpecialvalueGet(elem, NULL, (ProAppData *) &(elem_val->v.p));
	ERROR_CHECK (" ProElementSpecialvalueGet","UgFeatElemValueGet",err);
  
  elem_val->type = PRO_VALUE_TYPE_POINTER;
 
 return(err);      
}
/*====================================================================*\
Function: UgFeatElemRemove
Purpose: Removes a feature element from the element tree
\*====================================================================*/
ProError UgFeatElemRemove(ProElement tree, ProElempathItem *path, int size)
{
    ProElempath elem_path;
    ProElement elem;
    ProError err;

    err = ProElempathAlloc(&elem_path);
    ERROR_CHECK("ProElempathAlloc","UgFeatElemGet",err);

    err = ProElempathDataSet(elem_path,path,size);
    ERROR_CHECK("ProElempathDataSet","UgFeatElemGet",err);

    err = ProElemtreeElementGet(tree,elem_path,&elem);
    ERROR_CHECK("ProElemtreeElementGet","UgFeatElemValueGet",err);

    err = ProElemtreeElementRemove(tree,elem_path,&elem);
    ERROR_CHECK("ProElemtreeElementRemove","UgFeatElemRemove",err);

    err = ProElementFree(&elem);
    ERROR_CHECK("ProElementFree","UgFeatElemRemove",err);

    return(err);
}
/*====================================================================*\
Function: UgSweepSpineSktCreate
Purpose: Creates a spine sketch for a sweep first feature
\*====================================================================*/
ProError UgSweepSpineSktCreate(ProSection section)
{
    Pro2dSplinedef spline;
    Pro2dPnt pnt_ar[] = {{0.0,0.0},{5.0,5.0},{10.0,-5.0},{15.0,2.0}};
    int spl_id, dim_id;
    Pro2dPnt place_pnt = {7.5,0.0};
    ProSectionPointType pnt_types[] = {PRO_ENT_START,PRO_ENT_END};
    int ent_ids[2];
    ProError err;

    spline.type = PRO_2D_SPLINE;
    spline.tangency_type = PRO_2D_SPLINE_TAN_NONE;
    spline.n_points = 4;
    spline.point_arr = pnt_ar;
    spline.start_tang_angle = 0.0;
    spline.end_tang_angle = 0.0;

    err = ProSectionEntityAdd(section,(Pro2dEntdef *)&spline,&spl_id);
    ERROR_CHECK("ProSecitonEntityAdd","UgSweepSpineSktCreate",err);

    ent_ids[0] = ent_ids[1] = spl_id;
    err = ProSecdimCreate(section,ent_ids,pnt_types,2,
			  PRO_TK_DIM_PNT_PNT_HORIZ,place_pnt,&dim_id);
    ERROR_CHECK("ProSecdimCreate","UgSweepSpineSktCreate",err);

    ent_ids[0] = ent_ids[1] = spl_id;
    err = ProSecdimCreate(section,ent_ids,pnt_types,2,
			  PRO_TK_DIM_PNT_PNT_VERT,place_pnt,&dim_id);
    ERROR_CHECK("ProSecdimCreate","UgSweepSpineSktCreate",err);

    err = UgSectionRegenerate(section);

    return(err);
}
/*====================================================================*\
Function: UgSweepSectSktCreate
Purpose: Creates a section sketch for a constant section sweep
\*====================================================================*/
ProError UgSweepSectSktCreate(ProSection section)
{
    ProError err;
    Pro2dCircledef circle;
    int circle_id;
    ProSectionPointType pnt_types[] = {PRO_ENT_WHOLE};
    Pro2dPnt place_pnt = {0.0,0.0};
    int dim_id;
    ProIntlist ids;
    int n_ids;

    err = ProSectionEntityIdsGet(section,&ids,&n_ids);
    ERROR_CHECK("ProSectionEntityIdsGet","UgSweepSectSktCreate",err);

    ProTKPrintf("Number of section entities: %d\n",n_ids);

    circle.type = PRO_2D_CIRCLE;
    circle.center[0] = circle.center[1] = 0.0;
    circle.radius = 1.0;
    err = ProSectionEntityAdd(section,(Pro2dEntdef *)&circle,&circle_id);
    ERROR_CHECK("ProSecitonEntityAdd","UgSweepSectSktCreate",err);

/*--------------------------------------------------------------------*\
Dimension section and add location dimensions if necessary; Section can
be dimensioned with respect to the construction entities created by 
default (i.e. xy centerlines) although not needed here since the circle is
placed at the origin.
\*--------------------------------------------------------------------*/
    err = ProSecdimCreate(section,&circle_id,pnt_types,1,
			  PRO_TK_DIM_DIA,place_pnt,&dim_id);
    ERROR_CHECK("ProSecdimCreate","UgSweepSectSktCreate",err);

    err = UgSectionRegenerate(section);
    
    return(err);
}
/*====================================================================*\
Function: UgSectionRegenerate
Purpose: Regenerate a section
\*====================================================================*/
ProError UgSectionRegenerate(ProSection section)
{
    ProWSecerror sec_errs;
    ProError err;

    err = ProSecerrorAlloc(&sec_errs);
    ERROR_CHECK("ProSecerrorAlloc","UgSectionRegenerate",err);

    err = ProSectionSolve(section,&sec_errs);
    ERROR_CHECK("ProSectionSolve","UgSectionRegenerate",err);

    err = ProSecerrorFree(&sec_errs);
    ERROR_CHECK("ProSecerrorFree","UgSectionRegenerate",err);

    err = ProSecerrorAlloc(&sec_errs);
    ERROR_CHECK("ProSecerrorAlloc","UgSectionRegenerate",err);

    err = ProSectionRegenerate(section,&sec_errs);
    ERROR_CHECK("ProSectionRegenerate","UgSectionRegenerate",err);

    err = ProSecerrorAlloc(&sec_errs);
    ERROR_CHECK("ProSecerrorAlloc","UgSectionRegenerate",err);

    return(err);
}