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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProAssembly.h>
#include <ProMdl.h>
#include <ProMessage.h>
#include <ProModelitem.h>
#include <ProMenu.h>
#include <ProSelection.h>
#include <ProSolid.h>
#include <ProUtil.h>
#include <ProValue.h>
#include <ProWindows.h>
#include <ProSkeleton.h>
#include <ProModelitem.h>
#include <ProKinDrag.h>
#include <ProSelbuffer.h>
#include <ProSelection.h>


/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "TestFiletypes.h"
#include "UtilFiles.h"
#include "UtilMessage.h"
#include "UtilString.h"
#include "UtilNames.h"
#include "UtilCollect.h"
#include "UtilTree.h"
#include "UtilMenu.h"
#include "PTApplsUnicodeUtils.h"

#define PROKIN_TXT    "gen_msg.txt"
#define QCR_NAME      "snapshotinfo.inf"


FILE *fptr;
ProSelection select_drag_point (void);
ProError ProTestSnapshotInfoWrite ();
ProError  ProTestSnapshotInfo (ProName snapshot_name, ProAsmcomppath *path);
ProError ProTestSnapshotConstraintInfo (ProSnapshotConstraint constraint);

/*====================================================================*\
  Function : ProTestDrag()
  Purpose  : to test some ProAssembly functions
\*====================================================================*/
int ProTestDrag(ProMdl *model)
{
    ProError 		status;
    int                 menu_id;    /* The identifier of the created menu */
    int                 menu_action;
    int			ProTestPerformTransXMove(ProAppData	p_appdata, int option);
    int			ProTestSnapshotConstraintInfoGet(ProAppData	p_appdata, int option);
    int 		ProTestDeleteConstraints(ProAppData p_appdata, int option);
    int 		ProTestDeleteSnapshots(ProAppData p_appdata, int option);

    /* Load menu from file */
    status = ProMenuFileRegister((char *)"TkDrag", (char *)"tkdrag.mnu", &menu_id );
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestDrag()",
                        status, status != PRO_TK_NO_ERROR );

    /* Define menu buttons */

    ProMenubuttonActionSet((char *)"TkDrag", (char *)"Perform TransX Move",
        (ProMenubuttonAction)ProTestPerformTransXMove, model, 0 );
    ProMenubuttonActionSet((char *)"TkDrag", (char *)"Snapshot and Constraint Info",
        (ProMenubuttonAction)ProTestSnapshotConstraintInfoGet, model, 0 );
    ProMenubuttonActionSet((char *)"TkDrag", (char *)"Delete constraints",
        (ProMenubuttonAction)ProTestDeleteConstraints, model, 0 );
    ProMenubuttonActionSet((char *)"TkDrag", (char *)"Delete snapshots",
        (ProMenubuttonAction)ProTestDeleteSnapshots, model, 0 );
    ProMenubuttonActionSet((char *)"TkDrag", (char *)"TkDrag",
        (ProMenubuttonAction)ProMenuDelete, model, 0 );

    /* Run menu */
    status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"TkDrag", &menu_id );
    TEST_CALL_REPORT( "ProMenuCreate()", "ProTestDrag()",
                        status, status != PRO_TK_NO_ERROR );
    if( status == PRO_TK_NO_ERROR )
    {
        status = ProMenuProcess((char *)"TkDrag", &menu_action );
        TEST_CALL_REPORT( "ProMenuProcess()", "ProTestDrag()",
                            status, status != PRO_TK_NO_ERROR );
    }


    return (0);
}

/*====================================================================*\
  Function : ProTestPerformTransXMove()
  Purpose  : This function will perform the move for 
	     drag type PRO_KIN_ADVANCED_TRANS_X
\*====================================================================*/
int ProTestPerformTransXMove( 
    ProAppData		p_appdata,
    int			option
)
{
	
	ProError status = PRO_TK_NO_ERROR;
	ProAsmcomppath sel_path = { NULL, {PRO_VALUE_UNUSED}, 0};  
	ProModelitem sel_item = { PRO_TYPE_UNUSED, 0, NULL};
	Pro2dPnt *screenx_y = NULL;
	double d_x = 100.0, d_y = 50.0;
	int i = 0;
	ProSelection dragpoint = NULL;
	ProSelection selection_in = NULL;
	ProPoint3d sel_pnt = {0., 0., 0.};


	/* Starting the drag session */
	status = ProKinDragStart();
	TEST_CALL_REPORT( "ProKinDragStart()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	/* Setting environment for drag type PRO_KIN_ADVANCED_TRANS_X */
	status = ProKinDragEnvironmentSet (NULL, NULL,  
				PRO_KIN_ADVANCED_TRANS_X, NULL);
	TEST_CALL_REPORT( "ProKinDragEnvironmentSet()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProArrayAlloc (0, sizeof(Pro2dPnt), 1, (ProArray *)&screenx_y);
	TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	for ( i = 0 ; i < 40 ; i++)
	{
	  Pro2dPnt scr = {0., 0.};

	  d_x += 15;
          d_y += 20;
	  scr[0] = d_x;
	  scr[1] = d_y;

	  status = ProArrayObjectAdd ((ProArray*)&screenx_y, PRO_VALUE_UNUSED, 
			1, (void*)&scr);
	  TEST_CALL_REPORT( "ProArrayObjectAdd()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );
	}

	selection_in = select_drag_point ();        

	status = ProSelectionAsmcomppathGet(selection_in, &sel_path);
	TEST_CALL_REPORT( "ProSelectionAsmcomppathGet()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProSelectionModelitemGet (selection_in, &sel_item);
	TEST_CALL_REPORT( "ProSelectionModelitemGet()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProSelectionPoint3dGet(selection_in, sel_pnt);
	TEST_CALL_REPORT( "ProSelectionPoint()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProSelectionAlloc (&sel_path, &sel_item, &dragpoint);
	TEST_CALL_REPORT( "ProSelectionAlloc()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );
  
	status = ProSelectionPoint3dSet (sel_pnt, &dragpoint);
	TEST_CALL_REPORT( "ProSelectionPoint()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );
  
	/* Performing the move */
	status = ProKinDragPerformMove (dragpoint, screenx_y);
	TEST_CALL_REPORT( "ProKinDragPerformMove()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );
	if (status != PRO_TK_NO_ERROR)
	{
	  ProUtilMsgPrint("gen", "TEST %0s", "General error");
	}

	/* Stopping the drag session */
	status = ProKinDragStop();
	TEST_CALL_REPORT( "ProKinDragStop()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProSelectionFree( &selection_in);
	TEST_CALL_REPORT( "ProSelectionFree()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProSelectionFree( &dragpoint);
	TEST_CALL_REPORT( "ProSelectionFree()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

	status = ProArrayFree ((ProArray*)&screenx_y);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestPerformTransXMove()",
                      	status, status != PRO_TK_NO_ERROR );

    return 0;
}

ProSelection select_drag_point (void)
{
    ProSelFunctions     sel_funcs = {(ProSelectionPreFilter)NULL, 
                                     (ProSelectionPostFilter)NULL, 
                                     (ProSelectionPostSelact)NULL, 
                                     (ProAppData)NULL};
    ProSelection       *ref = NULL;
    int                 sel_ct = 0;
    ProError            retval = PRO_TK_NO_ERROR;
    char               *option = (char *)"part";

    retval = ProSelect ( option, 1, NULL, &sel_funcs, NULL, NULL, &ref, &sel_ct);

    if (retval == PRO_TK_NO_ERROR && sel_ct > 0)
        ProSelbufferClear();

    if (ref && retval == PRO_TK_NO_ERROR)
    {
        ProSelection  selection = 0;
        ProSelectionCopy(ref[0], &selection);
        return selection;
    }
    else
    {
	ProUtilMsgPrint("gen", "TEST %0s", "Select part");
        return NULL;
    }
}

/*====================================================================*\
  Function : ProTestSnapshotConstraintInfoGet()
  Purpose  : Writes snapshot and constraints info.
\*====================================================================*/
int ProTestSnapshotConstraintInfoGet( 
    ProAppData		p_appdata,
    int			option
)
{


	fptr = PTApplsUnicodeFopen (QCR_NAME, "w");

	if (fptr != NULL)
	{
	  ProTestSnapshotInfoWrite ();
	}

	if (fptr != NULL)
          fclose (fptr);

    return 0;
}

/*====================================================================*\
  Function : ProTestSnapshotInfoWrite()
  Purpose  : Writes snapshot info.
\*====================================================================*/

ProError ProTestSnapshotInfoWrite ()
{
  ProName *snap_names;
  ProAsmcomppath *path_arr;
  int i, num_snapshots;
  ProError status;

  status = ProKinDragStart();
  TEST_CALL_REPORT( "ProKinDragStart()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );


  status = ProKinDragSessionInquire();
  TEST_CALL_REPORT( "ProKinDragSessionInquire()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );

  /* Getting names of all the snapshots */
  status = ProKinDragSnapshotsNamesGet (&snap_names, &path_arr);  
  TEST_CALL_REPORT( "ProKinDragSnapshotsNamesGet()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );
  
  if (status == PRO_TK_NO_ERROR)
  {
        status = ProArraySizeGet (snap_names, &num_snapshots);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );

        ProTKFprintf (fptr,"      - Number of snapshots: %d",
                        num_snapshots );
        
	for (i=0;i<num_snapshots;i++)
        {
          ProTestSnapshotInfo (snap_names[i], &path_arr[i]);

          ProTKFprintf (fptr,"        ------------------------    \n" );
          
        }

        status = ProArrayFree ((ProArray *)&snap_names);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestSnapshotInfoWrite()",
              	status, status != PRO_TK_NO_ERROR );        

        status = ProArrayFree ((ProArray *)&path_arr);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );   

  }
  
  status = ProKinDragStop();
  TEST_CALL_REPORT( "ProKinDragStop()", "ProTestSnapshotInfoWrite()",
               	status, status != PRO_TK_NO_ERROR );  

  return PRO_TK_NO_ERROR;
}

ProError  ProTestSnapshotInfo (ProName snapshot_name, ProAsmcomppath *path)
{
 	ProCharName snap_name;
        ProSnapshotConstraint *constraints;
        int num_constraints, i;
        ProAsmcomppath *path_arr;
        ProMatrix *trfs;
	ProError status;
        int num_trfs;

        ProWstringToString (snap_name, snapshot_name);

        ProTKFprintf (fptr,"\n        - Name of the snapshot: %s",
                        snap_name);
  
  	/* Getting the constraints associated with each snapshot */     
        status = ProSnapshotConstraintsGet (snapshot_name, path,
                                                &constraints);
	TEST_CALL_REPORT( "ProSnapshotConstraintsGet()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );

        status = ProArraySizeGet (constraints, &num_constraints);
	TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );
       
        ProTKFprintf (fptr,"\n        - Number of constraints: %d",
                        num_constraints);
       
        for (i=0;i<num_constraints;i++)
        {
                ProTestSnapshotConstraintInfo (constraints[i]);
        }

        ProTKFprintf (fptr,
        "\n        - Transformation path and transformations matrices info. ");

        status = ProSnapshotTrfsGet (snapshot_name, path, &path_arr, &trfs);
	TEST_CALL_REPORT( "ProSnapshotTrfsGet()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );
        
        status = ProArraySizeGet (trfs, &num_trfs);
	TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );
        
        ProTKFprintf (fptr,
                        "\n          - Number of transformation matrices: %d \n",
                                 num_trfs);
  
        status = ProArrayFree ((ProArray *)&constraints);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );
        
        status = ProArrayFree ((ProArray *)&path_arr);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );
        
        status = ProArrayFree ((ProArray *)&trfs);
       	TEST_CALL_REPORT( "ProArrayFree()", "ProTestSnapshotInfo()",
                      	status, status != PRO_TK_NO_ERROR );

  return PRO_TK_NO_ERROR;
}


/*====================================================================*\
  Function : ProTestSnapshotConstraintInfo()
  Purpose  : Writes constraint info.
\*====================================================================*/
ProError ProTestSnapshotConstraintInfo (ProSnapshotConstraint constraint)
{
        int num_selections = 0;
        double value = 0.0;
	ProError status;

        ProTKFprintf (fptr ,
        "\n         +  -------- Constraint  info. ---------- ");
       
        ProTKFprintf (fptr , "\n          + Constraint  Type is   %d   "
							,constraint.type);

        ProTKFprintf (fptr , "\n          + Constraint  value:   %f   ",
         constraint.value);
        
        status = ProArraySizeGet (constraint.sel_array, &num_selections);
        
        if (status ==PRO_TK_NO_ERROR)
        {
          ProTKFprintf (fptr , "\n          + Number of selections:   %d   ",
                         num_selections);
        }

        ProTKFprintf (fptr , "\n          + Constraint is:   %s   ",
           (constraint.user_active == PRO_B_TRUE)?"User active":"Not user active");
        
        ProTKFprintf (fptr , "\n          + Constraint is:   %s   ",
           (constraint.valid == PRO_B_TRUE)?"Valid":"Invalid");
        
        if (constraint.type == PRO_SNAP_MOTION_AXIS_POS)
        {
          status = ProSnapshotConstraintEvaluate (&constraint, &value);
       	  TEST_CALL_REPORT( "ProSnapshotConstraintEvaluate()", 
			"ProTestSnapshotConstraintInfo()",
                      	status, status != PRO_TK_NO_ERROR );
        
          ProTKFprintf (fptr , "\n          + Current motion axis position:   %f   ",
                         value);
        }

  return PRO_TK_NO_ERROR;
}


/*====================================================================*\
  Function : ProTestDeleteConstraints()
  Purpose  : Writes snapshot and constraints info.
\*====================================================================*/
int ProTestDeleteConstraints( 
    ProAppData		p_appdata,
    int			option
)
{
  int i;
  ProError status;
  ProSnapshotConstraint *constraints;
  int num_constraints;
  ProFileName   wFilename;


  status = ProKinDragStart();
  TEST_CALL_REPORT( "ProKinDragStart()", "ProTestDeleteConstraints()",
               	status, status != PRO_TK_NO_ERROR );

  /* Getting input from the user */
  ProUtilMsgPrint ("gen", "TEST %0s", 
	"Enter snapshot name for which constraints are to be deleted");
	    
  if (ProMessageStringRead (PRO_FILE_NAME_SIZE, wFilename) != PRO_TK_NO_ERROR)
     return (0);

  ProMessageClear();

  /* Getting the constraints for the snapshot */
  status = ProSnapshotConstraintsGet (wFilename, NULL,
                                                &constraints);
  TEST_CALL_REPORT( "ProSnapshotConstraintsGet()", "ProTestDeleteConstraints()",
               	status, status != PRO_TK_NO_ERROR );

  if (status != PRO_TK_NO_ERROR)
  {
    ProUtilMsgPrint("gen", "TEST %0s", "general error in ProSnapshotConstraintsGet");
  }
  else
  {
    status = ProArraySizeGet (constraints, &num_constraints);
    TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSnapshotInfo()",
                     	status, status != PRO_TK_NO_ERROR );

    /* Deleting constraints associated with the snapshot */
    for (i=0;i<num_constraints;i++)
    {
      status = ProSnapshotConstraintDelete (wFilename,0);
      TEST_CALL_REPORT( "ProSnapshotConstraintDelete()", 
			"ProTestDeleteConstraints()",
                      	status, status != PRO_TK_NO_ERROR );
      if (status != PRO_TK_NO_ERROR)
      {
	ProUtilMsgPrint("gen", "TEST %0s",
		 "general error in ProSnapshotConstraintDelete");
      }
	
    }
	
  }

  status = ProKinDragStop();
  TEST_CALL_REPORT( "ProKinDragStop()", "ProTestDeleteConstraints()",
               	status, status != PRO_TK_NO_ERROR );

  return 0;
}

/*====================================================================*\
  Function : ProTestDeleteSnapshots()
  Purpose  : Writes snapshot and constraints info.
\*====================================================================*/
int ProTestDeleteSnapshots( 
    ProAppData		p_appdata,
    int			option
)
{
  ProName *snap_names;
  ProAsmcomppath *path_arr;
  int i, num_snapshots;
  ProError status;

  status = ProKinDragStart();
  TEST_CALL_REPORT( "ProKinDragStart()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );

  /* Getting all the snapshots */
  status = ProKinDragSnapshotsNamesGet (&snap_names, &path_arr);  
  TEST_CALL_REPORT( "ProKinDragSnapshotsNamesGet()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );
  
  if (status == PRO_TK_NO_ERROR)
  {
        status = ProArraySizeGet (snap_names, &num_snapshots);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );
      
  	/* Deleting all the snapshots */
	for (i=0;i<num_snapshots;i++)
        {
	/* Deleting all top-level snapshots */
	  status =   ProSnapshotDelete (snap_names[i],NULL);
          TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );         
        }

        status = ProArrayFree ((ProArray *)&snap_names);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestDeleteSnapshots()",
              	status, status != PRO_TK_NO_ERROR );        

        status = ProArrayFree ((ProArray *)&path_arr);
	TEST_CALL_REPORT( "ProArrayFree()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );   

  }

  status = ProKinDragStop();
  TEST_CALL_REPORT( "ProKinDragStop()", "ProTestDeleteSnapshots()",
               	status, status != PRO_TK_NO_ERROR );

  return 0;
}