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

#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProDraft.h>
#include <ProDirection.h>
#include <ProElement.h>
#include <ProSrfcollection.h>
#include <ProCrvcollection.h>
#include <ProMdl.h>
#include <ProGeomitem.h>
#include <ProSelbuffer.h>
#include <ProMessage.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProSurface.h>
#include <ProVariantFeat.h>
#include <ProAnnotationFeat.h>
#include <ProAnnotationElem.h>

#include <PTAFExamples.h>


/*====================================================================*\
  FUNCTION :	 TestPTAFExCreateDraftFeatureAccess()
  PURPOSE  :   Enable access to the Draft Feature from AE button	
\*====================================================================*/
uiCmdAccessState TestPTAFExCreateDraftFeatureAccess(uiCmdAccessMode access_mode)
{
  ProMdl mdl;
  ProMdlType mdltype;
  ProAnnotationElem annotelem;
  int featType = -1;
  ProSelection *sel=NULL;

/*---------------------------------------------------------------------*\
Test to See if the current model is a Part / Assembly
where annotation features exist
\*---------------------------------------------------------------------*/
  status = ProMdlCurrentGet(&mdl);
  if (status != PRO_TK_NO_ERROR) return (ACCESS_UNAVAILABLE);

  ProMdlTypeGet(mdl, &mdltype); 
  if ((mdltype != PRO_MDL_PART) && (mdltype != PRO_MDL_ASSEMBLY))
    return (ACCESS_UNAVAILABLE);

/*---------------------------------------------------------------------*\
Test to see if the Selection buffer if empty
Get the Annotation Element from the Selection buffer
\*---------------------------------------------------------------------*/
  status = PTAFExTestforSelectionsInBuffer();

  if (status != PRO_TK_NO_ERROR) return (ACCESS_UNAVAILABLE);
 
/*---------------------------------------------------------------------*\
User gets the ProSelection from the selection buffer
\*---------------------------------------------------------------------*/
  status = ProSelbufferSelectionsGet(&sel);
  PT_TEST_LOG_SUCC("PTAFExCreateRoundfromAE::ProSelbufferSelectionsGet ");

/*---------------------------------------------------------------------*\
Get ModelItem from the ProSelection
\*---------------------------------------------------------------------*/
  status = ProSelectionModelitemGet(sel[0], &annotelem);
  PT_TEST_LOG_SUCC("PTAFExCreateRoundfromAE::ProSelectionModelitemGet ");

  ProSelectionarrayFree (sel);

/*---------------------------------------------------------------------*\
Make sure Modelitem is an AE
\*---------------------------------------------------------------------*/
  if (annotelem.type != PRO_ANNOTATION_ELEM) return ACCESS_UNAVAILABLE;

/*---------------------------------------------------------------------*\
Get the feature type to be created
\*---------------------------------------------------------------------*/
  status = PTAFExGetFeatureType(&annotelem, &featType);

  if (featType == PTAFEX_PRO_FEAT_DRAFT) return (ACCESS_AVAILABLE);
  else return (ACCESS_UNAVAILABLE);
}



/*====================================================================*\
  FUNCTION :   PTAFExCreateDraftfromAE()
  PURPOSE  :   Callback to create Draft feature from AE	
\*====================================================================*/
ProError PTAFExCreateDraftfromAE()
{
  ProSelection *sel=NULL, ref_sel;
  ProAnnotationElem annotelem;
  int feature_type = -1;
  double draft_angle = -1;
  ProAnnotationReference *references=NULL;
  int num_refs = 0, i;
  ProGeomitem draft_reference;
  ProFeature feat;
  ProFeattype feat_type;
  ProCollection surf_coll;
  ProSrfcollinstr surf_coll_instr;
  ProSrfcollref surf_coll_ref;
  ProReference hinge_ref, direction_ref;
  ProBoolean is_surf_defined = PRO_B_FALSE, is_hinge_defined=PRO_B_FALSE, is_direction_defined=PRO_B_FALSE;
  ProAsmcomppath path;
  ProMdlType type;
  ProFeature inh_feat;

  inh_feat.owner = NULL;
  
/*---------------------------------------------------------------------*\
User gets the ProSelection from the selection buffer
\*---------------------------------------------------------------------*/
  status = ProSelbufferSelectionsGet(&sel);
  PT_TEST_LOG_SUCC("PTAFExCreateRoundfromAE::ProSelbufferSelectionsGet ");
  
/*---------------------------------------------------------------------*\
Get ModelItem from the ProSelection
\*---------------------------------------------------------------------*/
  status = ProSelectionModelitemGet(sel[0], &annotelem);
  PT_TEST_LOG_SUCC("PTAFExCreateRoundfromAE::ProSelectionModelitemGet ");

/*---------------------------------------------------------------------*\
If the selected modelitem owner is not the same as the component path
owner, and the component path owner is a part, the selection was
from an inheritance feature.
\*---------------------------------------------------------------------*/
  status = ProSelectionAsmcomppathGet (sel[0], &path);
  
  if (status == PRO_TK_NO_ERROR)
    {
      status = ProMdlTypeGet (path.owner, &type);
      if (type == PRO_MDL_PART)
	{
/*---------------------------------------------------------------------*\
Save the inheritance feature information.
\*---------------------------------------------------------------------*/
	  inh_feat.owner = path.owner;
	  inh_feat.id = path.comp_id_table [0];
	  inh_feat.type = PRO_FEATURE;
	}
    }

/*---------------------------------------------------------------------*\
Make sure Modelitem is an AE
\*---------------------------------------------------------------------*/
  if (annotelem.type != PRO_ANNOTATION_ELEM) return PRO_TK_NO_ERROR;

/*---------------------------------------------------------------------*\
If an AE, check for "round" parameter
\*---------------------------------------------------------------------*/
  status = PTAFExGetFeatureType(&annotelem, &feature_type);

  if (status == PRO_TK_NO_ERROR) {
/*---------------------------------------------------------------------*\
If the AE does not contain a parameter for feature type, quit function
\*---------------------------------------------------------------------*/
    if (feature_type != PTAFEX_PRO_FEAT_DRAFT) return PRO_TK_NO_ERROR;
	       
/*---------------------------------------------------------------------*\
If the AE contains parameter for the draft angle, get the value.
\*---------------------------------------------------------------------*/
    status = PTAFExGetFeatureValue(&annotelem, &draft_angle);

/*---------------------------------------------------------------------*\
Also, get the references for the AE
\*---------------------------------------------------------------------*/
    status = ProAnnotationelemReferencesCollect(&annotelem, 
						PRO_ANNOTATION_REF_ALL, 
						PRO_ANNOT_REF_FROM_ALL,
						&references);
    
    status = ProArraySizeGet((ProArray*)references, &num_refs);
    
    for (i=0; i<num_refs; i++) {
      
      ProAnnotationRefType my_ref_type = references[i].type; 
      
      if ( my_ref_type != PRO_ANNOT_REF_SINGLE )
	continue; 

/*---------------------------------------------------------------------*\ 
Get the Geomitem from the ProReference
\*---------------------------------------------------------------------*/
      status = ProReferenceToSelection(references[i].object.reference, &ref_sel);
  
      status = ProSelectionModelitemGet(ref_sel, (ProModelitem*)&draft_reference);
			
/*---------------------------------------------------------------------*\
Get the feature type that is the parent of the geomitem
\*---------------------------------------------------------------------*/
      status = ProGeomitemFeatureGet(&draft_reference, &feat);
      status = ProFeatureTypeGet(&feat, &feat_type);

/*---------------------------------------------------------------------*\
If the Geomitem Type is an edge this reference is the
direction reference for the draft
\*---------------------------------------------------------------------*/
      if (draft_reference.type == PRO_EDGE) {

/*---------------------------------------------------------------------*\
If the annotation element was from an inheritance feature, we need to 
convert the references to references in the top-level model.
\*---------------------------------------------------------------------*/
	if (inh_feat.owner != NULL)
	  {
	    ProGeomitem new_edge;

	    status = ProDatasharingfeatCopiedgeomitemFind (&inh_feat,
							   NULL,
							   &draft_reference,
							   &new_edge);
	    PT_TEST_LOG_SUCC ("ProDatasharingfeatCopiedgeomitemFind()");

	    ProReferenceAlloc (&direction_ref);
	    ProReferenceSet (direction_ref, NULL, &new_edge);
	  }
	else	
	  {
	    status = ProSelectionToReference(ref_sel, &direction_ref);
	  }
	ProSelectionFree (&ref_sel);
	is_direction_defined=PRO_B_TRUE;
      }
      
/*---------------------------------------------------------------------*\
If the Geomitem Type is a datum surface,
this reference is the hinge reference for the draft
\*---------------------------------------------------------------------*/
      if (draft_reference.type == PRO_SURFACE) {

	if (PTAFSurfaceIsDatum (&draft_reference)) {

/*---------------------------------------------------------------------*\
If the annotation element was from an inheritance feature, we need to 
convert the references to references in the top-level model.
\*---------------------------------------------------------------------*/
	  if (inh_feat.owner != NULL)
	    {
	      ProGeomitem new_surf;
	      
	      status = ProDatasharingfeatCopiedgeomitemFind (&inh_feat,
							     NULL,
							     &draft_reference,
							     &new_surf);
	      PT_TEST_LOG_SUCC  ("ProDatasharingfeatCopiedgeomitemFind()");
	      
	      ProReferenceAlloc (&hinge_ref);
	      ProReferenceSet (hinge_ref, NULL, &new_surf);
	    }
	  else	
	    {
	      status = ProSelectionToReference(ref_sel, &hinge_ref);
	    }
	  ProSelectionFree (&ref_sel);
	  is_hinge_defined = PRO_B_TRUE;
	}

	else {
	  ProReference surf_ref;
/*---------------------------------------------------------------------*\
If surface type is not a Datum Plane, the the reference is the surface to be 
drafted.
Create a surface collection instruction for SINGLE surface containing
this reference
\*---------------------------------------------------------------------*/
	  status = ProSrfcollinstrAlloc(PRO_SURFCOLL_SINGLE_SURF, PRO_B_FALSE, &surf_coll_instr);

	  status = ProSrfcollinstrIncludeSet ( surf_coll_instr, PRO_B_TRUE);

/*---------------------------------------------------------------------*\
If the annotation element was from an inheritance feature, we need to 
convert the references to references in the top-level model.
\*---------------------------------------------------------------------*/
	  if (inh_feat.owner != NULL)
	    {
	      ProGeomitem new_surf;
	      
	      status = ProDatasharingfeatCopiedgeomitemFind (&inh_feat,
							     NULL,
							     &draft_reference,
							     &new_surf);
	      PT_TEST_LOG_SUCC ("ProDatasharingfeatCopiedgeomitemFind()");
	      
	      ProReferenceAlloc (&surf_ref);
	      ProReferenceSet (surf_ref, NULL, &new_surf);
	    }
	  else	
	    {
	      status = ProSelectionToReference(ref_sel, &surf_ref);
	    }
	  ProSelectionFree (&ref_sel);

	  status = ProSrfcollrefAlloc(PRO_SURFCOLL_REF_SINGLE, 
				      surf_ref, 
				      &surf_coll_ref);

	  ProReferenceFree (surf_ref);

	  status = ProSrfcollinstrReferenceAdd(surf_coll_instr, surf_coll_ref);
					
	  status = ProSrfcollectionAlloc( &surf_coll );

	  status = ProSrfcollectionInstructionAdd( surf_coll, surf_coll_instr );					
	  is_surf_defined = PRO_B_TRUE;  
	}
      }
    }

/*---------------------------------------------------------------------*\
If all the references are present, then create the draft feature
\*---------------------------------------------------------------------*/
    if (is_surf_defined && is_hinge_defined && is_direction_defined)	  
      {	
/*---------------------------------------------------------------------*\
Create the Draft feature based on the attributes
\*---------------------------------------------------------------------*/
	if (inh_feat.owner == NULL)
	  status = ProMdlCurrentGet( &curr_mdl);
	else
	  curr_mdl = inh_feat.owner;

	status = PTAFExDraftCreate(curr_mdl, draft_angle, surf_coll, hinge_ref, direction_ref);

	ProAnnotationreferencearrayFree (references);
	ProReferenceFree (hinge_ref);
	ProReferenceFree (direction_ref);
	ProCollectionFree (&surf_coll);
      }
/*---------------------------------------------------------------------*\
If all the references were not present, display an error message to the user.
\*---------------------------------------------------------------------*/
    else
      { 
      ProMessageDisplay(message_file_init, 
			"PTAFEX ERROR %0s", 
			"All the required references not contained in the Annotation Element.");
      }
  }
  ProSelectionarrayFree (sel);
  
  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION :   PTAFExDraftCreate()
  PURPOSE  :   Create a draft using element tree.  Based on 
                UserSimpleDraftCreate() in UgSimpleDraftCreate.c (pt_userguide)
\*====================================================================*/
int PTAFExDraftCreate( ProMdl model, 
					   double draft_angle, 
					   ProCollection surf_coll, 
					   ProReference hinge_ref, 
					   ProReference direction_ref ) 
{
  ProElement pro_e_feature_tree;
  ProElement pro_e_feature_type;
  ProElement pro_e_draft_tweak_or_intersec;
  ProElement pro_e_draft_split;
  ProElement pro_e_std_surf_collection_appl;
  ProElement pro_e_direction_compound;
  ProElement pro_e_direction_reference;
  ProElement pro_e_direction_flip;
  ProElement pro_e_std_curve_collection_appl;
  ProElement pro_e_draft_constant_or_variable;
  ProElement pro_e_draft_include_tangent;
  ProElement pro_e_draft_side_1;
  ProElement pro_e_draft_neutral_object_type_1;
  ProElement pro_e_draft_dependent_1;
  ProElement pro_e_draft_angle_1;
  ProElement pro_e_draft_angles;
  ProElement pro_e_draft_side_2;
  ProElement pro_e_draft_neutral_object_type_2;
  ProElement pro_e_draft_dependent_2;
  ProElement pro_e_draft_angle_2;
  ProElement pro_e_draft_neutral_plane_1;

  status = ProElementAlloc ( PRO_E_FEATURE_TREE, &pro_e_feature_tree ); 
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  
  status = ProElementAlloc ( PRO_E_FEATURE_TYPE, &pro_e_feature_type );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_feature_type, 927 );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_feature_type );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_TWEAK_OR_INTERSEC, &pro_e_draft_tweak_or_intersec );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_tweak_or_intersec, 0 );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_tweak_or_intersec );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_SPLIT, &pro_e_draft_split );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_split, 0 );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_split );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_STD_SURF_COLLECTION_APPL, &pro_e_std_surf_collection_appl );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  
  status = ProElementCollectionSet( pro_e_std_surf_collection_appl, surf_coll );
  PT_TEST_LOG_SUCC( " ProElementCollectionSet " );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_std_surf_collection_appl );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DIRECTION_COMPOUND, &pro_e_direction_compound );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_direction_compound  );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DIRECTION_REFERENCE, &pro_e_direction_reference );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  
  status = ProElementReferenceSet( pro_e_direction_reference, direction_ref );
  PT_TEST_LOG_SUCC( " ProElementReferenceSet " );
  status = ProElemtreeElementAdd ( pro_e_direction_compound, NULL, pro_e_direction_reference );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DIRECTION_FLIP, &pro_e_direction_flip );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_direction_flip, 1 );
  status = ProElemtreeElementAdd ( pro_e_direction_compound, NULL, pro_e_direction_flip );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_CONSTANT_OR_VARIABLE, &pro_e_draft_constant_or_variable );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_constant_or_variable, 1 );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_constant_or_variable );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_INCLUDE_TANGENT, &pro_e_draft_include_tangent );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_include_tangent, 1 );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_include_tangent );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_SIDE_1, &pro_e_draft_side_1 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_side_1  );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_NEUTRAL_OBJECT_TYPE_1, &pro_e_draft_neutral_object_type_1 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );

/*---------------------------------------------------------------------*\
Using the Datum Plane as the draft hinge object type
\*---------------------------------------------------------------------*/
  status = ProElementIntegerSet ( pro_e_draft_neutral_object_type_1, 1 );
  status = ProElemtreeElementAdd ( pro_e_draft_side_1, NULL, pro_e_draft_neutral_object_type_1 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  
  status = ProElementAlloc ( PRO_E_DRAFT_NEUTRAL_PLANE_1, &pro_e_draft_neutral_plane_1 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementReferenceSet ( pro_e_draft_neutral_plane_1, hinge_ref );
  status = ProElemtreeElementAdd ( pro_e_draft_side_1, NULL, pro_e_draft_neutral_plane_1 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_DEPENDENT_1, &pro_e_draft_dependent_1 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_dependent_1, 0 );
  status = ProElemtreeElementAdd ( pro_e_draft_side_1, NULL, pro_e_draft_dependent_1 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_ANGLE_1, &pro_e_draft_angle_1 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  
  status = ProElementDoubleSet (  pro_e_draft_angle_1, draft_angle );
  status = ProElemtreeElementAdd ( pro_e_draft_side_1, NULL, pro_e_draft_angle_1 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_ANGLES, &pro_e_draft_angles );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElemtreeElementAdd ( pro_e_draft_side_1, NULL, pro_e_draft_angles  );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  
  status = ProElementAlloc ( PRO_E_DRAFT_SIDE_2, &pro_e_draft_side_2 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_draft_side_2  );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  
  status = ProElementAlloc ( PRO_E_DRAFT_NEUTRAL_OBJECT_TYPE_2, &pro_e_draft_neutral_object_type_2 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_neutral_object_type_2, 0 );
  status = ProElemtreeElementAdd ( pro_e_draft_side_2, NULL, pro_e_draft_neutral_object_type_2 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_STD_CURVE_COLLECTION_APPL, &pro_e_std_curve_collection_appl );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  
  status = ProElementAlloc ( PRO_E_DRAFT_DEPENDENT_2, &pro_e_draft_dependent_2 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementIntegerSet ( pro_e_draft_dependent_2, 0 );
  status = ProElemtreeElementAdd ( pro_e_draft_side_2, NULL, pro_e_draft_dependent_2 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_ANGLE_2, &pro_e_draft_angle_2 );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElementDoubleSet (  pro_e_draft_angle_2, 0.000000 );
  status = ProElemtreeElementAdd ( pro_e_draft_side_2, NULL, pro_e_draft_angle_2 );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = ProElementAlloc ( PRO_E_DRAFT_ANGLES, &pro_e_draft_angles );
  PT_TEST_LOG_SUCC( " ProElementAlloc " );
  status = ProElemtreeElementAdd ( pro_e_draft_side_2, NULL, pro_e_draft_angles  );
  PT_TEST_LOG_SUCC( " ProElemtreeElementAdd" );
  
  status = PTTestFeatureCreate_low ( model, pro_e_feature_tree  ); 
  PT_TEST_LOG_SUCC (" PTTestFeatureCreate_low"); 
  
  return status;
}