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


/*---------------------- Pro/Toolkit Includes ------------------------*/
#include <ProToolkit.h>
#include <ProMdl.h>
#include <ProUtil.h>
#include <ProFit.h>

#include "PTApplsUnicodeUtils.h"
/*---------------------- Function Prototypes -------------------------*/
ProError user_surf_clear ();
ProError user_dist_manifolds ();
ProError user_part_interference ();
ProError user_global_interference ();
int user_dump_interferences ();
int user_dump_mdl();

/*------------------------- External Data ----------------------------*/
extern char *UserUtilGenFilename(ProMdl p_obj, char *filext, char *filename);


/*================================================================*\
FUNCTION  : user_surf_clear
PURPOSE   : Computes the clearance between two surfaces.
\*================================================================*/
ProError user_surf_clear ()
{
    ProError    status;
    ProBoolean  interf;
    double      distance;
    Pro3dPnt    coord[2];
    ProSelection *sel;
    int         n_sel;
    ProFileName msg_fil;

    ProStringToWstring( msg_fil, "msg_uggeom.txt" );
    while (1)
    {
        status = ProMessageDisplay (msg_fil, "USER Select a face");
        ERROR_CHECK("user_surf_clear","ProMessageDisplay",status);
        status = ProSelect("face", 2, NULL, NULL, NULL, NULL, &sel, &n_sel);
        if (n_sel <= 1)
            return (PRO_TK_GENERAL_ERROR);
/*----------------------------------------------------------------*\
        Computes the clearance between the two selected surfaces.
\*----------------------------------------------------------------*/
        status = ProFitClearanceCompute(sel[0], PRO_FIT_INCLUDE_NONE, 
                                        sel[1], PRO_FIT_INCLUDE_NONE,
                                        PRO_FIT_WHOLE_SURFACE, NULL, PRO_B_FALSE,
                                        &distance, NULL, &interf, coord);
        ERROR_CHECK("user_surf_clear","ProFitClearanceCompute", status);

        status = ProMessageDisplay (msg_fil, "USER Distance is %0(5.3)f", &distance);
        ERROR_CHECK("user_surf_clear","ProMessageDisplay",status);

        if (interf)
        {
            status = ProMessageDisplay (msg_fil, "USER Interference exists");
	        ERROR_CHECK("user_surf_clear","ProMessageDisplay",status);
        }
    }
    return (PRO_TK_NO_ERROR);
}

/*================================================================*\
FUNCTION  : user_dist_manifolds
PURPOSE   : Computes the critical distance between two objects.
\*================================================================*/
ProError user_dist_manifolds ()
{
    ProError    status;
    ProSelection *sel;
    int          n_sel;
    double       distance;
    Pro2dPnt uv1, uv2;
    Pro3dPnt xyz1, xyz2;
    ProFileName msg_fil;

    ProStringToWstring( msg_fil, "msg_uggeom.txt" );
   
    status = ProMessageDisplay (msg_fil, "USER %0s", "Select two entities");
    ERROR_CHECK("user_dist_manifolds","ProMessageDisplay",status);

    status = ProSelect("point,edge,curve,surface", 2, NULL, NULL, NULL, NULL, &sel, &n_sel);
    if (n_sel < 2)
        return (PRO_TK_GENERAL_ERROR);

/*----------------------------------------------------------------*\
    Compute the distance between the two manifolds.
\*----------------------------------------------------------------*/
    status = ProSelectionWithOptionsDistanceEval(sel[0], PRO_B_TRUE, sel[1], PRO_B_TRUE, uv1, uv2, xyz1, xyz2, &distance);
    ERROR_CHECK("user_dist_manifolds","ProSelectionWithOptionsDistanceEval",status);

    if (status)
    {
        status = ProMessageDisplay (msg_fil, "USER Distance is %0(5.3)f", 
				&distance);
        ERROR_CHECK("user_dist_manifolds","ProMessageDisplay",status);
    }
    else
    {
        status = ProMessageDisplay (msg_fil, "USER %0s", 
					"No min/max distances found");
        ERROR_CHECK("user_dist_manifolds","ProMessageDisplay",status);
    }
    return (PRO_TK_NO_ERROR);
}

/*================================================================*\
FUNCTION  : user_part_interference
PURPOSE   : Computes the interference between two parts.
\*================================================================*/
ProError user_part_interference ()
{
    ProError      status;
    ProSelection *sel;
    int           n_sel;
    wchar_t       w_str[5];
    char          str[100], a_str[5];
    double        volume;
    FILE         *fp;
    char          fname[PRO_NAME_SIZE+4];
    wchar_t       w_fname[PRO_NAME_SIZE+4];
    ProMdl        p_model;
    ProFileName   msg_fil;
    ProInterferenceData interf_data;

    status = ProMdlCurrentGet(&p_model);
    ERROR_CHECK("user_part_interference","pro_get_current_object",
			(p_model == NULL));
    if (p_model == NULL) return (PRO_TK_E_NOT_FOUND);

    ProStringToWstring( msg_fil, "msg_uggeom.txt" );
    status = ProMessageDisplay (msg_fil, "USER %0s", "Select two parts");
    ERROR_CHECK("user_part_interference","ProMessageDisplay",status);

    status = ProSelect("part", 2, NULL, NULL, NULL, NULL, &sel, &n_sel);
/*----------------------------------------------------------------*\
    Compute the interference between the two parts.
\*----------------------------------------------------------------*/
    status = ProFitInterferenceCompute(sel[0], sel[1], PRO_B_FALSE, PRO_B_FALSE, &interf_data);
    ERROR_CHECK("user_part_interference","ProFitInterferenceCompute",status);
    if (status != PRO_TK_NO_ERROR)
        return (PRO_TK_GENERAL_ERROR);

    if (NULL == interf_data)
    {
        status = ProMessageDisplay (msg_fil, "USER %0s", 
				"No interference was detected.");
        ERROR_CHECK("user_part_interference","ProMessageDisplay",status);
        return (PRO_TK_NO_ERROR);
    }

    ProTKSprintf (str, "Interference found. Display? [Y]:");
    status = ProMessageDisplay (msg_fil,"USER %0s", str);
    ERROR_CHECK("user_part_interference","ProMessageDisplay",status);

    if (!ProMessageStringRead (4, w_str))
    {
        ProWstringToString (a_str, w_str);
        if (a_str[0] != 'y' || a_str[0] != 'Y')
            return (PRO_TK_NO_ERROR);
    }

    UserUtilGenFilename (p_model, ".intf", fname);
    if ((fp = PTApplsUnicodeFopen (fname, "w")) == NULL)
        return (PRO_TK_GENERAL_ERROR);
    ProTKFprintf (fp, "Interference in ");
    user_dump_mdl (fp, p_model);
    ProTKFprintf (fp, "\n\n");

/*----------------------------------------------------------------*\
    Compute the interference volume.
\*----------------------------------------------------------------*/
    status = ProFitInterferencevolumeCompute(interf_data, &volume);
    ERROR_CHECK("user_part_interference","pro_compute_volume",status);
    user_dump_interferences (fp, sel, volume);

/*----------------------------------------------------------------*\
    Highlight the interference regions.
\*----------------------------------------------------------------*/
    status = ProFitInterferencevolumeDisplay(interf_data, PRO_COLOR_EDGE_HIGHLIGHT);
    ERROR_CHECK("user_part_interference","pro_display_interf_volume",status);

    ProTKSprintf (str, "Total Interference Volume = %lf", volume);
    status = ProMessageDisplay (msg_fil, "USER %0s", str);
    ERROR_CHECK("user_part_interference","ProMessageDisplay",status);

/*----------------------------------------------------------------*\
    Release the memory for the interference volume.
\*----------------------------------------------------------------*/
    fclose (fp);

    ProStringToWstring (w_fname, fname);
    status = ProInfoWindowDisplay (w_fname, NULL, NULL);
    ERROR_CHECK("user_part_interference","ProInfoWindowDisplay",status);

    status = ProInterferenceDataFree(interf_data);
    ERROR_CHECK("user_part_interference","ProInterferenceDataFree",status);

    return (PRO_TK_NO_ERROR);
}

/*================================================================*\
FUNCTION  : user_global_interference
PURPOSE   : Computes the global interference within an assembly.
\*================================================================*/
ProError user_global_interference ()
{
    ProError               status;
    ProSelection          *sel;
    int                    n_intf_parts, *n_part_surfs, i;
    wchar_t                w_str[5];
    char                   str[100], a_str[5];
    double                 volume;
    FILE                  *fp;
    char                   fname[PRO_NAME_SIZE+4];
    wchar_t                w_fname[PRO_NAME_SIZE+4];
    ProFileName            msg_fil;
    ProMdl                 p_model;
    ProInterferenceInfo   *interf_info_arr;

    ProStringToWstring( msg_fil, "msg_uggeom.txt" );

    status = ProMdlCurrentGet(&p_model);
    ERROR_CHECK("user_global_interference","pro_get_current_object",
                        (p_model == NULL));
    if (p_model == NULL) return (PRO_TK_E_NOT_FOUND);

/*----------------------------------------------------------------*\
    Compute the interference within the assembly.
\*----------------------------------------------------------------*/
    status = ProFitGlobalinterferenceCompute((ProAssembly)p_model, PRO_FIT_SUB_ASSEMBLY, 
                                             PRO_B_FALSE, PRO_B_FALSE, PRO_B_FALSE, 
                                             &interf_info_arr);
    ERROR_CHECK("user_global_interference","ProFitGlobalinterferenceCompute",status);

    if (status != PRO_TK_NO_ERROR)
        return (PRO_TK_GENERAL_ERROR);

    status = ProArraySizeGet(interf_info_arr, &n_intf_parts);
    if (n_intf_parts == 0)
    {
       status = ProMessageDisplay (msg_fil, "USER %0s", 
				"No interference was detected.");
       ERROR_CHECK("user_global_interference","ProMessageDisplay",status);
    }

    ProTKSprintf (str, 
     "%d interfering part pairs found. Display interference pair volumes? [Y]:",
     n_intf_parts);

    ProMessageDisplay (msg_fil, "USER %0s", str);
    if (!ProMessageStringRead (4, w_str))
    {
        ProWstringToString (a_str, w_str);
        if (a_str[0] != 'y' || a_str[0] != 'Y')
            return (PRO_TK_NO_ERROR);
    }
    UserUtilGenFilename (p_model, ".intf", fname);
    if ((fp = PTApplsUnicodeFopen (fname, "w")) == NULL)
        return (PRO_TK_GENERAL_ERROR);
    ProTKFprintf (fp, "Interference in ");
    user_dump_mdl (fp, p_model);
    ProTKFprintf (fp, "\n\n");
    for (i = 0; i < n_intf_parts; i++)
    {

/*----------------------------------------------------------------*\
        Compute the interference volumes.
\*----------------------------------------------------------------*/
      status = ProFitInterferencevolumeCompute(interf_info_arr[i].interf_data, 
                                               &volume);
        ERROR_CHECK("user_global_interference","ProFitInterferencevolumeCompute",status);
        user_dump_interferences (fp, interf_info_arr[i].part_1, 
                                     interf_info_arr[i].part_2, volume);

/*----------------------------------------------------------------*\
        Highlight the interference regions.
\*----------------------------------------------------------------*/
        status = ProFitInterferencevolumeDisplay(interf_info_arr[i].interf_data, 
                                                 PRO_COLOR_EDGE_HIGHLIGHT);
        ERROR_CHECK("user_global_interference","ProFitInterferencevolumeDisplay",status);

        ProTKSprintf (str, "Interference pair %d of %d: Volume = %0.2lf: Continue? [y]:", i+1, n_intf_parts, volume);
        status = ProMessageDisplay (msg_fil, "USER %0s", str);
        ERROR_CHECK("user_global_interference","ProMessageDisplay",status);

        if (!ProMessageStringRead (4, w_str))
        {
            ProWstringToString (a_str, w_str);
            if (a_str[0] != 'y' || a_str[0] != 'Y')
            {
                fclose (fp);
                return (PRO_TK_NO_ERROR);
            }
        }

/*----------------------------------------------------------------*\
        Release the memory for the interference volume.
\*----------------------------------------------------------------*/
    }
    fclose (fp);

    ProStringToWstring (w_fname, fname);
    status = ProInfoWindowDisplay (w_fname, NULL, NULL);
    ERROR_CHECK("user_global_interference","ProInfoWindowDisplay",status);

    status = ProInterferenceInfoProarrayFree(interf_info_arr);

    return (PRO_TK_NO_ERROR);
}


/*================================================================*\
FUNCTION  : user_dump_interferences
PURPOSE   : Writes the interference information into a file.
\*================================================================*/
int user_dump_interferences (fp, part_1, part_2, volume)
FILE          *fp;
ProSelection   part_1, part_2;
double         volume;
{
    int m;
    ProMdl mdl;
    ProModelitem modelitem;
    ProAsmcomppath cmp_path;
    ProError status;

    ProTKFprintf (fp, "Interfering Parts:\n");
    ProTKFprintf (fp, "\t ");
    status = ProSelectionModelitemGet(part_1, &modelitem);
    user_dump_mdl (fp, modelitem.owner);

    status = ProSelectionAsmcomppathGet(part_1, &cmp_path);
    ProTKFprintf (fp, "\tmemb_id_tab[");
    for (m = 0; m < cmp_path.table_num; m++)
    {
        ProTKFprintf (fp, "%d", cmp_path.comp_id_table[m]);
        if (m < cmp_path.table_num-1)
            ProTKFprintf (fp, ",");
    }
    ProTKFprintf (fp, "]\n");
    ProTKFprintf (fp, "\t ");
    status = ProSelectionModelitemGet(part_2, &modelitem);
    user_dump_mdl (fp, modelitem.owner);

    status = ProSelectionAsmcomppathGet(part_2, &cmp_path);
    ProTKFprintf (fp, "\tmemb_id_tab[");
    for (m = 0; m < cmp_path.table_num; m++)
    {
        ProTKFprintf (fp, "%d", cmp_path.comp_id_table[m]);
        if (m < cmp_path.table_num-1)
            ProTKFprintf (fp, ",");
    }
    ProTKFprintf (fp, "]\n");
    ProTKFprintf (fp, "\tInterfering Volume: %0.2lf\n\n", volume);
    return(0);
}

int user_dump_mdl (fp, p_model)
FILE          *fp;
ProMdl         p_model;
{    
    char                 name[PRO_MDLNAME_SIZE], type[PRO_MDLEXTENSION_SIZE];
	ProMdlName           modelName;
	ProMdlExtension      modelExtension;

    if (p_model == NULL)
        return (0);
    
	ProMdlMdlnameGet(p_model, modelName);        
	
    ProMdlExtensionGet(p_model, modelExtension);
    ProTKFprintf (fp, "%s.%s:", ProWstringToString (name, modelName),
        ProWstringToString (type, modelExtension));
    return (0);
}