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

#include <ProToolkit.h>
#include <ProAnnotationFeat.h>
#include <ProAnnotationElem.h>
#include <ProMenuBar.h>
#include <ProPopupmenu.h>
#include <ProSelbuffer.h>
#include <ProSurface.h>
#include <ProGtol.h>
#include <ProUIMessage.h>
#include <ProParameter.h>
#include <ProMdl.h>

#include <PTAFExamples.h>
#include <ProTKRunTime.h>
#include <PTApplsUnicodeUtils.h>

/*====================================================================*\
  FUNCTION :   PTTestAccessInfoMfgTemplate()
  PURPOSE  :   Enable/Disable access to the manufacturing template info button
\*====================================================================*/
uiCmdAccessState PTTestAccessInfoMfgTemplate (uiCmdAccessMode access_mode)
{
  ProMdl mdl;
  ProMdlType type;

  status = ProMdlCurrentGet (&mdl);
  PT_TEST_LOG_SUCC ("ProMdlCurrentGet()");
  if (status != PRO_TK_NO_ERROR) return (ACCESS_UNAVAILABLE);

  status = ProMdlTypeGet (mdl, &type);
  PT_TEST_LOG_SUCC ("ProMdlTypeGet()");

  if (type != PRO_MDL_PART && type != PRO_MDL_ASSEMBLY)
	return ACCESS_INVISIBLE;

  return ACCESS_AVAILABLE;		  
}

#define MSGFIL L"pt_mfgtemplatebom.txt"

int PTANCPPParamsList();
int PTMfgTemplateAEWriteBOM ();

#define MFG_TEMPLATE_NAME L"MFG_AE_TEMPLATE_NAME"

typedef struct
{
  ProLine template_type;
  ProVector orientation;
  ProName orientation_label;
  ProBoolean is_completed;  /* runtime flag - indicates we processed this AE
			     into the BOM already */
} PTMfgTemplateOrientationData;

typedef struct
{
  ProAnnotationElem ae;
  ProAnnotationType type;

  int feat_id;
  void* app_data;
} PTAEInfo;

typedef ProError (*PTAEAppDataCollectionFunction) (ProAnnotationElem* ae,
												   void** app_data);

typedef struct 
{
  PTAEAppDataCollectionFunction app_collection_function;
  PTAEInfo* collected_aes;
} PTAECollectionData;

/*====================================================================*\
  FUNCTION :   PTMfgTemplateAEInfoCollect()
  PURPOSE  :   Collect information about the mfg template AE
\*====================================================================*/
ProError PTMfgTemplateAEInfoCollect (ProAnnotationElem* ae,
				     void** app_data)
{
  PTMfgTemplateOrientationData* data;
  ProParameter param;
  ProParamvalue pvalue;

  data = (PTMfgTemplateOrientationData*) calloc (1, 
												 sizeof (PTMfgTemplateOrientationData));
  
/*---------------------------------------------------------------------*\
Extract the value of the template name parameter
\*---------------------------------------------------------------------*/
  status = ProParameterInit (ae, MFG_TEMPLATE_NAME, &param);
  PT_TEST_LOG_SUCC ("ProParameterInit()");
  
  status = ProParameterValueWithUnitsGet(&param, &pvalue, NULL);
  PT_TEST_LOG_SUCC ("ProParameterValueWithUnitsGet()");

  ProWstringCopy (pvalue.value.s_val, data->template_type, PRO_VALUE_UNUSED);

/*---------------------------------------------------------------------*\
Not implemented; for future use
\*---------------------------------------------------------------------*/
  data->orientation [0] = 0.0;
  data->orientation [1] = 0.0;
  data->orientation [2] = 0.0;
  
  data->orientation_label [0] = (wchar_t)0;

  data->is_completed = PRO_B_FALSE;

  *app_data = data;

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION :   PTAEIsMfgTemplate()
  PURPOSE  :   Identifies if the AE is a manufacturing template AE
\*====================================================================*/
ProError PTAEIsMfgTemplate (ProAnnotationElem* ae, ProAppData data)
{
  ProAnnotationType type;
  ProParameter param;

/*---------------------------------------------------------------------*\
Check the annotation element type
\*---------------------------------------------------------------------*/
  status = ProAnnotationelemTypeGet (ae, &type);
  PT_TEST_LOG_SUCC ("ProAnnotationelemTypeGet()");
  
  if (type != PRO_ANNOT_TYPE_CUSTOM)
	return PRO_TK_CONTINUE;
  
/*---------------------------------------------------------------------*\
Check for the mfg template parameter
\*---------------------------------------------------------------------*/
  status = ProParameterInit (ae, MFG_TEMPLATE_NAME, &param);
  PT_TEST_LOG ("ProParameterInit()", status, 
			   status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

  if (status != PRO_TK_NO_ERROR)
	return PRO_TK_CONTINUE;

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION :   PTAEInfoCollect()
  PURPOSE  :   Collect information on annotation elements
\*====================================================================*/
ProError PTAEInfoCollect (ProAnnotationElem* ae, ProError status,
							ProAppData data)
{
  PTAECollectionData* ae_data = (PTAECollectionData*) data;
  PTAEInfo info;
  ProFeature feat;

/*---------------------------------------------------------------------*\
Collect basic AE information: owner, id, feature that owns it
\*---------------------------------------------------------------------*/
  info.ae.owner = ae->owner;
  info.ae.id = ae->id;
  info.ae.type = ae->type;
  
  status = ProAnnotationelemTypeGet (ae, &info.type);
  PT_TEST_LOG_SUCC ("ProAnnotationelemTypeGet()");

  status = ProAnnotationelemFeatureGet (ae, &feat);
  PT_TEST_LOG_SUCC ("ProAnnotationelemFeatureGet()");

  info.feat_id = feat.id;

/*---------------------------------------------------------------------*\
Use the stored callback function to collect specific needed data
\*---------------------------------------------------------------------*/
  if (ae_data->app_collection_function != NULL)
    (*ae_data->app_collection_function) (ae, (void**) &info.app_data);

  status = ProArrayObjectAdd ((ProArray*)&ae_data->collected_aes,
							  -1, 1, &info);
  PT_TEST_LOG_SUCC ("ProArrayObjectAdd()");

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION :   PTMfgTemplateAEPrint()
  PURPOSE  :   Print the properties of the mfg template AE (JavaScript)
\*====================================================================*/
ProError  PTMfgTemplateAEPrint (FILE* fp, int parent, int node, PTAEInfo* info)
{
  ProFeature feature;
  ProName ae_name, af_name;
  ProMdlName owner_name;
  ProCharName c_ae_name, c_af_name;
  char c_owner_name[PRO_MDLNAME_SIZE];
  char* owner_type;
  ProMdlType type;

/*---------------------------------------------------------------------*\
Extract needed info from the AE
\*---------------------------------------------------------------------*/
  ProModelitemNameGet (&info->ae, ae_name);
  ProWstringToString (c_ae_name, ae_name);

  feature.owner = info->ae.owner;
  feature.type = PRO_FEATURE;
  feature.id = info->feat_id;

  status = ProModelitemNameGet (&feature, af_name);
  PT_TEST_LOG_SUCC ("ProModelitemNameGet()");
  ProWstringToString (c_af_name, af_name);

  if (status != PRO_TK_NO_ERROR)
    ProTKSprintf (c_af_name, "with id %d", feature.id);

  status = ProMdlMdlnameGet (info->ae.owner, owner_name);
  ProWstringToString (c_owner_name, owner_name);

  status = ProMdlTypeGet (info->ae.owner, &type);
  if (type == PRO_MDL_PART)
    owner_type = "PRT";
  else
    owner_type = "ASM";

/*---------------------------------------------------------------------*\
Print the JavaScript tree node.
First half includes the node level, parent, and label
Second half produces proep: URL to highlight the AE
\*---------------------------------------------------------------------*/
  ProTKFprintf (fp, "d.add(%d,%d,'Annotation element %s (belongs to feature %s)',",
	   node, parent, c_ae_name, c_af_name); 

  ProTKFprintf (fp, "'proep://local_proesession?oid=%s.%s&item=annotation_element&id=%d&action=highlight');\n", c_owner_name, owner_type, info->ae.id);

  return PRO_TK_NO_ERROR;
}

#define MFGINFOFILENAME "mfgtemplateinfo.html"

/*====================================================================*\
  FUNCTION :   PTMFGTemplateBOMHTMLWrite()
  PURPOSE  :   Print the mfg template BOM to the HTML file
\*====================================================================*/
ProError PTMFGTemplateBOMHTMLWrite (ProMdl mdl, PTAECollectionData data)
{
  ProMdlName name;
  char c_name[PRO_MDLNAME_SIZE];
  ProMdlType type;
  char* type_str;
  FILE* fp;
  int size;
  int index;

  int node_counter = 1;
  int parent_node = 0;
  
/*---------------------------------------------------------------------*\
Open and print the HTML introductory lines
\*---------------------------------------------------------------------*/
  fp = PTApplsUnicodeFopen (MFGINFOFILENAME, "w");
  
  ProTKFprintf (fp, "<html>\n");
  ProTKFprintf (fp, "<head>\n");
  ProTKFprintf (fp, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /=\"\">\n");
  ProTKFprintf (fp, "<title>Manufaturing template info</title>\n");
  ProTKFprintf (fp, "<link rel=\"StyleSheet\" href=\"dtree.css\" type=\"text/css\"/>\n");
  ProTKFprintf (fp, "<script type=\"text/javascript\" src=\"dtree.js\"></script>\n");
  
  ProTKFprintf (fp, "</head>\n");
  ProTKFprintf (fp, "<body>\n");

/*---------------------------------------------------------------------*\
Print the title of the page using the model name & type
\*---------------------------------------------------------------------*/ 
  status = ProMdlMdlnameGet (mdl, name);
  PT_TEST_LOG_SUCC ("ProMdlMdlnameGet()");
  
  ProWstringToString (c_name, name);
  
  status = ProMdlTypeGet (mdl, &type);
  PT_TEST_LOG_SUCC ("ProMdlTypeGet()");
  
  if (type == PRO_MDL_PART)
    type_str = "Part";
  else
    type_str = "Assembly";
  
  ProTKFprintf (fp, "<h2>Manufacturing template information for %s %s</h2>\n", type_str, c_name);
 
/*---------------------------------------------------------------------*\
Print the JavaScript tree initialization code
\*---------------------------------------------------------------------*/ 
  ProTKFprintf (fp, "<div class=\"dtree\">\n");
  ProTKFprintf (fp, "<script type=\"text/javascript\">\n");
  ProTKFprintf (fp, "<!--\n");
  
  ProTKFprintf (fp, "d = new dTree('d');\n");
  ProTKFprintf (fp, "d.config.useIcons = false;\n");
  ProTKFprintf (fp, "d.config.useCookies = false;\n");
  ProTKFprintf (fp, "d.config.useSelection = false;\n");
  
  ProTKFprintf (fp, "d.add(0,-1,'');\n");
  
/*---------------------------------------------------------------------*\
For each AE, extract the MFG template data
\*---------------------------------------------------------------------*/ 
  status = ProArraySizeGet (data.collected_aes, &size);
  PT_TEST_LOG_SUCC ("ProArraySizeGet()");
    
  for (index = 0; index < size; index ++)
    {
      PTMfgTemplateOrientationData* mfg_data;
      ProCharPath template_name;
      int j, n_instances;
      
      
      mfg_data = (PTMfgTemplateOrientationData*)
	data.collected_aes [index].app_data;

/*---------------------------------------------------------------------*\
Runtime flag indicates if we've already traversed and printed this AE
\*---------------------------------------------------------------------*/      
      if (mfg_data->is_completed)
	continue;
      
      ProWstringToString (template_name, mfg_data->template_type);
      
      n_instances = 1;

/*---------------------------------------------------------------------*\
The first loop through the remaining AE's is to generate a count of the
AE's that use a certain template name
\*---------------------------------------------------------------------*/  
      for (j = index + 1; j < size; j ++)
	{
	  PTMfgTemplateOrientationData* second_mfg_data;
	  int result;
	  
	  second_mfg_data = (PTMfgTemplateOrientationData*)
	    data.collected_aes [j].app_data;
	  
	  ProWstringCompare (mfg_data->template_type,
			     second_mfg_data->template_type,
			     PRO_VALUE_UNUSED,
			     &result);
	  
	  if (result == 0)
	    {
	      n_instances ++;
	    }
	}

/*---------------------------------------------------------------------*\
Print the tree parent node, containing the count
\*---------------------------------------------------------------------*/  
      ProTKFprintf (fp, "d.add(%d,0,'Template: %d x\t%s','');\n",node_counter,n_instances,template_name);
      parent_node = node_counter;
      node_counter++;

/*---------------------------------------------------------------------*\
Print the current AE as the first child to the parent node
\*---------------------------------------------------------------------*/  
      PTMfgTemplateAEPrint (fp, parent_node, node_counter, &data.collected_aes[index]);
      node_counter++;
      mfg_data->is_completed = PRO_B_TRUE;
      
/*---------------------------------------------------------------------*\
Loop through the remaining AE's again and print each matching AE as a child
of the parent node
\*---------------------------------------------------------------------*/ 
      for (j = index + 1; j < size; j ++)
	{
	  PTMfgTemplateOrientationData* second_mfg_data;
	  int result;
	  
	  second_mfg_data = (PTMfgTemplateOrientationData*)
	    data.collected_aes [j].app_data;
	  
	  ProWstringCompare (mfg_data->template_type,
			     second_mfg_data->template_type,
			     PRO_VALUE_UNUSED,
			     &result);
	  
	  if (result == 0)
	    {
	      PTMfgTemplateAEPrint (fp, parent_node, node_counter, &data.collected_aes[j]);
	      second_mfg_data->is_completed = PRO_B_TRUE;
	      node_counter ++;
	    }
	}
    }
  
/*---------------------------------------------------------------------*\
Free the collected AE data
\*---------------------------------------------------------------------*/ 
  for (index = 0; index < size; index ++)
    {
      PTMfgTemplateOrientationData* mfg_data;
      
      mfg_data = (PTMfgTemplateOrientationData*)
	data.collected_aes [index].app_data;
      
      free (mfg_data);
    }
  ProArrayFree ((ProArray*)&data.collected_aes);
  
/*---------------------------------------------------------------------*\
Complete the HTML BOM
\*---------------------------------------------------------------------*/ 
  ProTKFprintf (fp, "document.write(d);\n");
  
  ProTKFprintf (fp, "//-->\n");
  ProTKFprintf (fp, "</script>\n");
  
  ProTKFprintf (fp, "</div>\n");

  ProTKFprintf (fp, "</body>\n");
  ProTKFprintf (fp, "</html>\n");
  
  fclose (fp);

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION :   PTMfgTemplateAEWriteBOM()
  PURPOSE  :   Menu button to write and display HTML BOM for mfg templates
\*====================================================================*/
int PTMfgTemplateAEWriteBOM ()
{
  ProMdl mdl;
  PTAECollectionData data;
  ProFileName filename;
  ProPath dir_path, path;
  int window_id;
  ProCharPath char_path;

/*---------------------------------------------------------------------*\
Collect the AE's in the model that match the criteria (only MFG template
AE's should be collected).
\*---------------------------------------------------------------------*/
  status = ProMdlCurrentGet (&mdl);
  PT_TEST_LOG_SUCC ("ProMdlCurrentGet()");
  if (status != PRO_TK_NO_ERROR) return (ACCESS_UNAVAILABLE);

  data.app_collection_function = PTMfgTemplateAEInfoCollect;

  status = ProArrayAlloc (0, sizeof (PTAEInfo),
			  5, (ProArray*) &data.collected_aes);

  status = ProSolidAnnotationelemsVisit (mdl, 
					 PTAEInfoCollect,
					 PTAEIsMfgTemplate,
					 (ProAppData)&data);
  PT_TEST_LOG_SUCC ("ProSolidAnnotationelemsVisit()");

/*---------------------------------------------------------------------*\
Output and display the BOM HTML
\*---------------------------------------------------------------------*/
  if (status == PRO_TK_NO_ERROR)
  {
    PTMFGTemplateBOMHTMLWrite (mdl, data);
    
    ProDirectoryCurrentGet (dir_path);
    
    ProStringToWstring (path, "file://");
    
    ProWstringConcatenate (dir_path, path, 
			   PRO_VALUE_UNUSED);
    
    ProStringToWstring (filename, MFGINFOFILENAME);
    ProWstringConcatenate (filename, path, 
			   PRO_VALUE_UNUSED);
    
    ProWstringToString (char_path, path);
    
    ProWindowCurrentGet (&window_id);
    
    ProWindowURLShow(window_id, path);	
  }
 
  return PRO_TK_NO_ERROR;
}