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


#include <ProToolkit.h>
#include <ProParameter.h>
#include <ProMaterial.h>
#include <ProParamDriver.h>
#include <ProUtil.h>
#include <ProModelitem.h>
#include <ProRelSet.h>
#include <ProTKRunTime.h>
#include <PTApplsUnicodeUtils.h>


#define PTTestResfileWrite(str)\
  ProTKFprintf(file_ptr, "%s\n", str);

#define PTTestResfileStringWrite(str)\
  ProTKFprintf(file_ptr, "%s", str);

static char line [500];

static ProParamtableSet* tableset_array;

static PTUDFExParamInfoFormat format;

static FILE* file_ptr;

/*====================================================================*\
FUNCTION: PTUDFExParamvalueWrite_very_low
PURPOSE:  Write the value of a parameter value.
\*====================================================================*/
ProError PTUDFExParamvalueWrite_very_low (ProParamvalue* value,
					 ProBoolean short_version)
{
  ProParamvalueType  type;
  double d_val;
  int i_val;
  short b_val;
  ProLine s_val;
  char val [PRO_LINE_SIZE];
  
  status = ProParamvalueTypeGet (value, &type);
  PT_TEST_LOG_SUCC ("ProParamvalueTypeGet()");

  switch (type)
    {
    case PRO_PARAM_DOUBLE:
      {
	status = ProParamvalueValueGet (value, type, (void *) &d_val);
	PT_TEST_LOG_SUCC ("ProParamvalueValueGet()");

	ProTKSprintf (line, (short_version ? "%8.10lf" : 
			"        - Param value (double): %8.10lf"), d_val);
	break;
      }
    case PRO_PARAM_STRING:
      {
	status = ProParamvalueValueGet (value, type, (void *) s_val);
	PT_TEST_LOG_SUCC ("ProParamvalueValueGet()");
	
	ProTKSprintf (line, (short_version ? "%s" :
			"        - Param value (string): %s"), 
		 ProWstringToString (val, s_val));
	break;
      }
    case PRO_PARAM_INTEGER:
      {
	status = ProParamvalueValueGet (value, type, (void *) &i_val);
	PT_TEST_LOG_SUCC ("ProParamvalueValueGet()");

	ProTKSprintf (line, (short_version ? "%d" :
			"        - Param value (integer): %d"), i_val);
	break;
      }
    case PRO_PARAM_BOOLEAN:
      {
	status = ProParamvalueValueGet (value, type, (void *) &b_val);
	PT_TEST_LOG_SUCC ("ProParamvalueValueGet()");

	ProTKSprintf (line, (short_version ? "%s":
			"        - Param value (boolean): %s"), 
		 b_val?"TRUE":"FALSE");
	break;
      }
    case PRO_PARAM_NOTE_ID:
      {
	status = ProParamvalueValueGet (value, type, (void *) &i_val);
	PT_TEST_LOG_SUCC ("ProParamvalueValueGet()");

	ProTKSprintf (line, (short_version ? "%d" :
			"        - Param value (note_id): %d"), i_val);
	break;
      }
    case PRO_PARAM_VOID:
      {
	ProTKSprintf (line, (short_version ? "":"      + Param value (void)"));
	break;
      }
    default:
      return PRO_TK_GENERAL_ERROR;
    }
  if (short_version)
    {
      PTTestResfileStringWrite (line);
    }
  else
    {
      PTTestResfileWrite (line);
    }
  
  return PRO_TK_NO_ERROR;

}

/*====================================================================*\
FUNCTION: PTUDFExParamvalueShortversionWrite_low
PURPOSE:  Write only the value of a parameter value.
\*====================================================================*/
ProError PTUDFExParamvalueShortversionWrite_low (ProParamvalue* value)
{
  PTUDFExParamvalueWrite_very_low (value, PRO_B_TRUE);
}

/*====================================================================*\
FUNCTION: PTUDFExParamvalueCSVWrite_low
PURPOSE:  Write the value and type of a parameter value in a CSV format.
\*====================================================================*/
ProError PTUDFExParamvalueCSVWrite_low (ProParamvalue* value)
{
  switch (value->type)
    {
    case PRO_PARAM_INTEGER:
      PTTestResfileStringWrite ("INTEGER");
      break;
    case PRO_PARAM_DOUBLE:
      PTTestResfileStringWrite ("DOUBLE");
      break;
    case PRO_PARAM_BOOLEAN:
      PTTestResfileStringWrite ("BOOLEAN");
      break;
    case PRO_PARAM_STRING:
      PTTestResfileStringWrite ("STRING");
      break;
    case PRO_PARAM_VOID:
      PTTestResfileStringWrite ("VOID");
      break;
    }

  PTTestResfileStringWrite (",");
  PTUDFExParamvalueWrite_very_low (value, PRO_B_TRUE);
  PTTestResfileStringWrite (",");
}

/*====================================================================*\
FUNCTION: PTUDFExParamvalueWrite_low
PURPOSE:  Write the value and type of a parameter value in a deascriptive
          text format.
\*====================================================================*/
ProError PTUDFExParamvalueWrite_low (ProParamvalue* value)
{
 PTUDFExParamvalueWrite_very_low (value, PRO_B_FALSE);
}

/*====================================================================*\
FUNCTION: PTUDFExParamlimitWrite_low
PURPOSE:  Write text information about a parameter upper or lower bound.
\*====================================================================*/
static ProError PTUDFExParamlimitWrite_low (char* label, ProParamLimit* limit)
{
  char*  limit_string;

  ProTKSprintf (line,  "      + %s Value Info:", label);
  PTTestResfileWrite (line);

  switch (limit->type)
    {
    case PRO_PARAM_UNLIMITED:
      limit_string = "Unlimited";
      break;
    case PRO_PARAM_GREATER_THAN:
      limit_string = "Greater than";
      break;
    case PRO_PARAM_GREATER_THAN_OR_EQUAL:
      limit_string = "Greater than or equal to";
      break;
    case PRO_PARAM_LESS_THAN:
      limit_string = "Less than";
      break;
    case PRO_PARAM_LESS_THAN_OR_EQUAL:
      limit_string = "Less than or equal to";
      break;
    }

  ProTKSprintf (line,"      + Parameter Limit Type : %s", limit_string);
  PTTestResfileWrite (line); 
  
  PTUDFExParamvalueWrite_low (&limit->value);

  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExParamtableEntryWrite_low
PURPOSE:  Write text information about a parameter table entry.
\*====================================================================*/
static ProError PTUDFExParamtableEntryWrite_low (ProParamtableEntry entry)
{
  ProName name;
  ProCharName c_name;
  ProParamvalue value;
  ProParamLimit min, max;

  PTTestResfileWrite ("-----------------------------------------------------");

  status = ProParamtableentryNameGet (entry, name);
  PT_TEST_LOG_SUCC ("ProParamtableentryNameGet()");

  ProWstringToString (c_name, name);

  status = ProParamtableentryValueGet (entry, &value);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParamtableentryValueGet()");

  ProTKSprintf (line, "          * Entry: %s, value: ", c_name);
  PTTestResfileStringWrite (line); 

  if (status == PRO_TK_NO_ERROR)
    {
      PTUDFExParamvalueShortversionWrite_low (&value);
      PTTestResfileWrite ("");
    }
  else
    {
      PTTestResfileWrite ("NULL");
    }

  status = ProParamtableentryRangeGet (entry, &min, &max);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParamtableentryRangeGet()");
  
  if ( status == PRO_TK_NO_ERROR)
    {
      PTTestResfileStringWrite ("          ");  /* Indent */   
      PTUDFExParamlimitWrite_low ("Minimum", &min);
      PTTestResfileStringWrite ("          ");  /* Indent */   
      PTUDFExParamlimitWrite_low ("Maximum", &max);
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExParamtableSetWrite_low
PURPOSE:  Write text information about a parameter table set.
\*====================================================================*/
ProError PTUDFExParamtableSetWrite_low (ProParamtableSet table_set, ProBoolean include_entries)
{
  ProPath table_path;
  ProName label;
  char buff [500];
  int i, size;
  ProParamtableEntry* entries;

  PTTestResfileWrite ("  - Member of a restricted table set:");

  status = ProParamtablesetTablepathGet (table_set, table_path);
  PT_TEST_LOG_SUCC ("ProParamtablesetTablepathGet()");

  ProWstringToString (buff, table_path);
  
  ProTKSprintf (line, "        = Name/path: %s", buff);
  PTTestResfileWrite (line);
  
  status = ProParamtablesetLabelGet (table_set, label);
  PT_TEST_LOG_SUCC ("ProParamtablesetLabelGet()");

  ProWstringToString (buff, label);
  
  ProTKSprintf (line, "        = Label param: %s", buff);
  PTTestResfileWrite (line);

  status = ProParamtablesetEntriesGet (table_set, &entries);
  PT_TEST_LOG_SUCC ("ProParamtablesetEntriesGet()");

  status = ProArraySizeGet (entries, &size);
  PT_TEST_LOG_SUCC ("ProArraySizeGet()");

  if (include_entries)
    {
      ProTKSprintf (line, "        = %d entries: ", size);
      PTTestResfileWrite (line);

      for (i = 0; i < size; i ++)
	{
	  PTUDFExParamtableEntryWrite_low (entries[i]);
	}
    }
  else
    {
      ProTKSprintf (line, "        = %d entries. ", size);
      PTTestResfileWrite (line);
    }

  status = ProParamtableentryProarrayFree (entries);
  PT_TEST_LOG_SUCC ("ProParamtableentryProarrayFree()");
}

/*====================================================================*\
FUNCTION: PTUDFExWriteModelitem
PURPOSE:  Write information about a modelitem or parameter owner.
\*====================================================================*/
static ProError PTUDFExWriteModelitem (ProModelitem* item)
{
  ProMdlType mdl_type;
  char c_item_type [PRO_NAME_SIZE];
  ProMdlName mdl_name;
  char c_file_name [PRO_MDLNAME_SIZE];

  status = ProMdlMdlnameGet (item->owner, mdl_name);
  ProWstringToString (c_file_name, mdl_name);

  status = ProMdlTypeGet (item->owner, &mdl_type);
  switch (mdl_type)
    {
    case PRO_MDL_PART:
      strcat (c_file_name, ".prt");
      break;
    case PRO_MDL_ASSEMBLY:
      strcat (c_file_name, ".asm");
      break;
    }

  switch (item->type)
    {
    case PRO_TYPE_UNUSED:
    case PRO_PART:
    case PRO_ASSEMBLY:
      strcpy (c_item_type, "");
      break;
    case PRO_FEATURE:
      strcpy (c_item_type, "Feature");
      break;
    case PRO_ANNOTATION_ELEM:
      strcpy (c_item_type, "Annotation Elem");
      break;
    }
  
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      if (item->type == PRO_TYPE_UNUSED)
	{
	  ProTKSprintf (line, "model %s", c_file_name);
	}
      else
	{
	  ProTKSprintf (line, "%s id %d (%s)", c_item_type, 
		   item->id, c_file_name);
	}
      PTTestResfileWrite (line);
      break;
      
    case PT_UDF_EX_PARAM_INFO_CSV:
      ProTKSprintf (line, "%s,%s,%d,", c_file_name, c_item_type, 
	       item->id);
      PTTestResfileStringWrite (line);
      break;
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteParameterBasics
PURPOSE:  Write the parameter name & owner details.
\*====================================================================*/
static ProError PTUDFExWriteParameterBasics (ProParameter* param)
{
  char c_name [PRO_NAME_SIZE*4];
  ProModelitem owner_item;
  ProMdl owner_mdl;

  ProWstringToString (c_name, param->id);

  switch (param->owner.type)
    {
    case PRM_MODEL:
      owner_item.owner = param->owner.who.model;
      owner_item.id = -1;
      owner_item.type = PRO_TYPE_UNUSED;
      break;
    case PRM_ITEM:
      memcpy (&owner_item, &param->owner.who.item, sizeof (ProModelitem));
      break;
    }

  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      PTTestResfileWrite ("---------------------------------------------------------");
      ProTKSprintf (line, "Parameter: %s owned by ", c_name); 
      PTTestResfileStringWrite (line);
      
      PTUDFExWriteModelitem (&owner_item);
  
      break;

    case PT_UDF_EX_PARAM_INFO_CSV:
      ProTKSprintf (line, "%s,", c_name);
      PTTestResfileStringWrite (line);

      PTUDFExWriteModelitem (&owner_item);
      break;
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteParameterValue
PURPOSE:  Write the parameter value and units details.
\*====================================================================*/
static ProError PTUDFExWriteParameterValue (ProParamvalue* value, char* unit_name)
{
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      if (strlen (unit_name) > 0)
	ProTKSprintf (line, "      + Scaled Value, in %s:", unit_name);
      else
	ProTKSprintf (line, "      + Value");
      PTTestResfileWrite (line);
      PTUDFExParamvalueWrite_low (value);
    
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      PTUDFExParamvalueCSVWrite_low (value);

      ProTKSprintf (line, "%s,",unit_name);
      PTTestResfileStringWrite (line);

      break;
    }
}

/*====================================================================*\
FUNCTION: PTUDFExWriteDescription
PURPOSE:  Write the parameter description.
\*====================================================================*/
static ProError PTUDFExWriteDescription (wchar_t* description)
{
  char* c_descr;
  int length;

  status = ProWstringLengthGet (description, &length);
  
  c_descr = (char*) calloc (3* (length + 1), sizeof (char));
      
  ProWstringToString (c_descr, description);
  
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      ProTKSprintf (line, "      + Description: %s", c_descr);
      PTTestResfileWrite (line);
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      ProTKSprintf (line, "%s,", c_descr);
      PTTestResfileStringWrite (line);
      break;
    }
      
  free (c_descr);
 
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteDesignation
PURPOSE:  Write the parameter designation status.
\*====================================================================*/
static ProError PTUDFExWriteDesignation (ProBoolean is_designated)
{
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      ProTKSprintf (line, "      + %s", is_designated ? "Designated.": "Not designated.");
      PTTestResfileWrite (line);
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      ProTKSprintf (line, "%s,", is_designated ? "TRUE": "FALSE");
      PTTestResfileStringWrite (line);
      break;
    }
 
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteEnumeration
PURPOSE:  Write the details about an enumeration restriction.
\*====================================================================*/
static ProError PTUDFExWriteEnumeration (ProBoolean is_enum, ProParamvalue* values_array)
{
  int num_values, i;
  ProParamvalue value;

  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      ProTKSprintf (line, "      + %s ", (is_enum == PRO_B_TRUE) ? "Enumerated:":"Not enumerated." );
      PTTestResfileWrite (line);
  
      if (is_enum == PRO_B_TRUE)
	{
	  ProArraySizeGet ( values_array, &num_values);
	  for (i = 0 ; i< num_values; i++)
	    {
	      value = values_array[i];
	      PTTestResfileStringWrite ("\t");
	      PTUDFExParamvalueWrite_low (&value);
	    }
	}
      break;

     case PT_UDF_EX_PARAM_INFO_CSV:
       if (is_enum == PRO_B_TRUE)
	 {
	   ProArraySizeGet ( values_array, &num_values);
	   for (i = 0 ; i< num_values; i++)
	     {
	       value = values_array[i];
	       PTUDFExParamvalueShortversionWrite_low (&value);
	       
	       if (i != num_values - 1)
		 PTTestResfileStringWrite ("|");
	     }
	 }
       PTTestResfileStringWrite (",");
       break;
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteRange
PURPOSE:  Write the details about  range restriction.
\*====================================================================*/
static ProError PTUDFExWriteRange (ProBoolean has_range, ProParamLimit* min, ProParamLimit* max)
{
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      ProTKSprintf (line, "      + %s " , (has_range == PRO_B_TRUE) ? "Has range." : "Doesn't have range.");
      PTTestResfileWrite (line);
  
      if ( has_range == PRO_B_TRUE)
	{
	  PTUDFExParamlimitWrite_low ("Minimum", min);
	  PTUDFExParamlimitWrite_low ("Maximum", max);
	}
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      if ( has_range == PRO_B_TRUE)
	{
	  switch (min->type)
	    {
	    case PRO_PARAM_UNLIMITED:
	      PTTestResfileStringWrite ("(|");
	      break;
	    case PRO_PARAM_GREATER_THAN:
	      PTTestResfileStringWrite ("(");
	      PTUDFExParamvalueShortversionWrite_low (&min->value);
	      PTTestResfileStringWrite ("|");
	      break;
	    case PRO_PARAM_GREATER_THAN_OR_EQUAL:
	      PTTestResfileStringWrite ("[");
	      PTUDFExParamvalueShortversionWrite_low (&min->value);
	      PTTestResfileStringWrite ("|");
	      break;
	    }
	  
	    switch (max->type)
	    {
	    case PRO_PARAM_UNLIMITED:
	      PTTestResfileStringWrite (")");
	      break;
	    case PRO_PARAM_LESS_THAN:
	      PTUDFExParamvalueShortversionWrite_low (&max->value);
	      PTTestResfileStringWrite (")");
	      break;
	    case PRO_PARAM_LESS_THAN_OR_EQUAL:
	      PTUDFExParamvalueShortversionWrite_low (&max->value);
	      PTTestResfileStringWrite ("]");
	      break;
	    }	      
	}
      PTTestResfileStringWrite (",");
      break;
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteTable
PURPOSE:  Write informaiton about the table set label for this parameter.
\*====================================================================*/
static ProError PTUDFExWriteTable (ProName label)
{
  char c_label [PRO_NAME_SIZE * 4];

  ProWstringToString (c_label, label);

  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      if (strlen (c_label) > 0)
	{
	  ProTKSprintf (line, "      + Member of table row %s", c_label);
	  PTTestResfileWrite (line);
	}
      else
	{
	  PTTestResfileWrite ("      + Doesn't belong to a table.");
	}
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      if (strlen (c_label) > 0)
	{
	  ProTKSprintf (line, "%s", c_label);
	  PTTestResfileStringWrite (line);
	}
      PTTestResfileStringWrite (",");
      break;
    }
  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExWriteParameterEnd
PURPOSE:  Close the section relating to the current parameter.
\*====================================================================*/
static ProError PTUDFExWriteParameterEnd ()
{
  switch (format)
    {
    case PT_UDF_EX_PARAM_INFO_TEXT:
      PTTestResfileWrite ("---------------------------------------------------------");
      break;
    case PT_UDF_EX_PARAM_INFO_CSV:
      PTTestResfileWrite ("");
      break;
    }
  return (PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION: PTUDFExParameterWrite_low
PURPOSE:  Write all details about a single parameter.
\*====================================================================*/
ProError PTUDFExParameterWrite_low (ProParameter* param)
{
   ProBoolean is_designated= PRO_B_FALSE;
   ProParamvalue value, *array_values;
   char unit_name [PRO_LINE_SIZE];
   ProUnititem units;
   ProBoolean has_range, is_enum;
   ProParamLimit max, min;
   ProParamtableSet table_set;
   wchar_t* description;
   ProName label;
   ProError descr_status;
   
   /* Basics (name, owner) */
   PTUDFExWriteParameterBasics (param);

   /* Value */
  status = ProParameterScaledvalueGet (param, &value);
  PT_TEST_LOG_SUCC ("ProParameterScaledvalueGet()");
  
  status = ProParameterUnitsGet ( param, &units);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParametersUnitsGet");

  if (status == PRO_TK_NO_ERROR)
     ProWstringToString ( unit_name, units.name);
  else
    strcpy (unit_name, "");

  PTUDFExWriteParameterValue (&value, unit_name);

  /* Description */
  descr_status = ProParameterDescriptionGet (param, &description);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParameterDescriptionGet()");

  if (descr_status != PRO_TK_NO_ERROR)
    description = L"";

  PTUDFExWriteDescription (description);

  if (descr_status == PRO_TK_NO_ERROR)
    {
      ProWstringFree (description);
    }

  /* Designation */
  status = ProParameterDesignationVerify (param, &is_designated);
  PT_TEST_LOG_SUCC ("ProParameterDesignationVerify()");

  PTUDFExWriteDesignation (is_designated);

  /* Enumeration */
  status = ProParameterIsEnumerated ( param, &is_enum, &array_values);
  PT_TEST_LOG_SUCC ("ProParameterIsEnumerated");

  PTUDFExWriteEnumeration (is_enum, array_values);

  if (status == PRO_TK_NO_ERROR)
    {
      ProArrayFree ((ProArray *) &array_values);
    }

  /* Range */ 
   status = ProParameterRangeGet (param, &has_range, &min, &max);
   PT_TEST_LOG_SUCC ("ProParameterRangeGet");

   PTUDFExWriteRange (has_range, &min, &max);
 
   /* Table set */
   status = ProParameterTablesetGet (param, &table_set);
   PT_TEST_LOG_NOT_FOUND_OK ("ProParameterTablesetGet");

  if (status == PRO_TK_NO_ERROR)
     {
       status = ProParamtablesetLabelGet (table_set, label);
       PT_TEST_LOG_SUCC ("ProParamtablesetLabelGet()");
     }
   else
     {
       ProStringToWstring (label, "");
     }

   PTUDFExWriteTable (label);

   PTUDFExWriteParameterEnd ();

   return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION: PTUDFExParamVisitAction
PURPOSE:  Visit action to write all details about  parameters.
\*====================================================================*/
ProError PTUDFExParamVisitAction (ProParameter* param, ProError status, ProAppData data)
{
  ProMdl owner_model;

  PTUDFExParameterWrite_low (param);

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION: PTUDFExParamtableSetsWrite_low
PURPOSE:  Write details about an array of parameter sets.
\*====================================================================*/
static ProError PTUDFExParamtableSetsWrite_low (ProParamtableSet* table_sets)
{
  int i, size;

  status = ProArraySizeGet (table_sets, &size);
  PT_TEST_LOG_SUCC ("ProArraySizeGet()");

  for (i = 0; i < size; i ++)
    {
      PTUDFExParamtableSetWrite_low (table_sets [i], PRO_B_TRUE);
    }

  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExParametersWrite_low
PURPOSE:  Write details about the parameters and parameter sets on 
          this owner.
\*====================================================================*/
ProError PTUDFExParametersWrite_low (ProModelitem* owner)
{

  status = ProArrayAlloc (0, sizeof (ProParamtableSet), 1, 
			  (ProArray*) &tableset_array);
  PT_TEST_LOG_SUCC ("ProArrayAlloc()");

  status = ProParameterVisit (owner, NULL, 
			      (ProParameterAction)PTUDFExParamVisitAction,
			      NULL);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParameterVisit()");

  PTUDFExParamtableSetsWrite_low (tableset_array);
  
  status = ProParamtablesetProarrayFree (tableset_array);
  PT_TEST_LOG_SUCC ("ProParamtablesetProarrayFree()");

  return PRO_TK_NO_ERROR;
}

/*====================================================================*\
FUNCTION: PTUDFExMdlParamtableSetsWrite_low
PURPOSE:  Write details about all the parameter sets available to this model.
\*====================================================================*/
static ProError PTUDFExMdlParamtableSetsWrite_low (ProMdl mdl)
{
  ProParamtableSet* table_sets;
  int i, size;

  status = ProMdlParamtablesetsCollect (mdl, &table_sets);
  PT_TEST_LOG_SUCC ("ProMdlParamtablesetsCollect()");

  PTUDFExParamtableSetsWrite_low (table_sets);
 
  status = ProParamtablesetProarrayFree (table_sets);
  PT_TEST_LOG_SUCC ("ProParamtablesetProarrayFree()");

  return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION: PTUDFExParamtablesetByLabelGet
PURPOSE:  Find a parameter set, by name.
\*====================================================================*/
ProError PTUDFExParamtablesetByLabelGet (ProMdl mdl, wchar_t* name, 
					ProParamtableSet* set)
{
  ProParamtableSet* table_sets;
  int i, size;
  ProName label;
  int result;
  ProBoolean found = PRO_B_FALSE;

  status = ProMdlParamtablesetsCollect (mdl, &table_sets);
  PT_TEST_LOG_SUCC ("ProMdlParamtablesetsCollect()");

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

  status = ProArraySizeGet (table_sets, &size);
  PT_TEST_LOG_SUCC ("ProArraySizeGet()");

  for (i = 0; i < size; i ++)
    {
      status = ProParamtablesetLabelGet (table_sets[i], label);
      PT_TEST_LOG_SUCC ("ProParamtablesetLabelGet()");

      status = ProWstringCompare (label, name, PRO_VALUE_UNUSED, &result);
      PT_TEST_LOG_SUCC ("ProWstringCompare()");

      if (result == 0)
	{
	  *set = table_sets[i];
	  found = PRO_B_TRUE;
	  continue;
	}

      ProParamtablesetFree (table_sets[i]);
    }

  ProArrayFree ((ProArray*)&table_sets);
 
  if (found)
    return (PRO_TK_NO_ERROR);
  else
    return (PRO_TK_E_NOT_FOUND);
}

/*====================================================================*\
FUNCTION: PTUDFExParamInfoWrite
PURPOSE:  Write a text or CSV file with parameter info.
\*====================================================================*/
ProError PTUDFExParamInfoWrite (ProModelitem* param_owner,
				PTUDFExParamInfoFormat f,
				ProFileName output_file,
				ProBoolean append,
				ProParameterFilter filter_action,
				ProAppData app_data)
{
  ProError ret_status;
  char filename [100];
  char* flags = "w";

  format = f;

  ProWstringToString (filename, output_file);

  if (append)
    flags = "a";

  file_ptr = PTApplsUnicodeFopen (filename, flags);

  status = ProArrayAlloc (0, sizeof (ProParamtableSet), 1, 
			  (ProArray*) &tableset_array);
  PT_TEST_LOG_SUCC ("ProArrayAlloc()");

  status = ProParameterVisit (param_owner, filter_action, 
			      (ProParameterAction)PTUDFExParamVisitAction,
			      app_data);
  PT_TEST_LOG_NOT_FOUND_OK ("ProParameterVisit()");

  ret_status = status;

  PTUDFExParamtableSetsWrite_low (tableset_array);
  
  status = ProParamtablesetProarrayFree (tableset_array);
  PT_TEST_LOG_SUCC ("ProParamtablesetProarrayFree()");

  fclose (file_ptr);

  return (ret_status);
}

/*====================================================================*\
FUNCTION: PTUDFExAEConstraintsWrite
PURPOSE:  Write a text format file with table-imposed constraints.
\*====================================================================*/
ProError PTUDFExAEConstraintsWrite (ProModelitem* param_owner,
				    ProFileName output_file,
				    ProBoolean append)
{
  ProError ret_status;
  char filename [100];
  char* flags = "w";
  ProRelset rel_set;
  wchar_t** constraints;
  int size, i;
  char c_constraint [PRO_LINE_SIZE * 4];

  format = PT_UDF_EX_PARAM_INFO_TEXT;

  ProWstringToString (filename, output_file);

  if (append)
    flags = "a";

  file_ptr = PTApplsUnicodeFopen (filename, flags);

  /* Write constraints on the AE parameters */
  status = ProModelitemToRelset (param_owner, &rel_set);
  PT_TEST_LOG_NOT_FOUND_OK ("ProModelitemToRelset()");
  
  if (status == PRO_TK_NO_ERROR)
    {
      status = ProRelsetConstraintsGet (&rel_set, &constraints);
      PT_TEST_LOG_NOT_FOUND_OK ("ProRelsetConstraintsGet()");
      
      if (status == PRO_TK_NO_ERROR)
	{
	  status = ProArraySizeGet (constraints, &size);
	  PT_TEST_LOG_SUCC ("ProArraySizeGet()");

	  if (size > 0)
	    {
	      ProTKSprintf (line, "There are %d table-imposed constraints on ", 
		       size, c_constraint);
	      PTTestResfileStringWrite (line);

	      PTUDFExWriteModelitem (param_owner);
	    }
	  
	  for (i = 0; i < size; i ++)
	    {
	      ProWstringToString (c_constraint, constraints[i]);
	      
	      ProTKSprintf (line, "    + Constraint %d: %s", i + 1, c_constraint);
	      PTTestResfileWrite (line);
	    }
	  
	  ProWstringproarrayFree (constraints);

	  fclose (file_ptr);

	  return (PRO_TK_NO_ERROR);
	}
    }
  ProTKSprintf (line, "There are no table-imposed constraints on ");
  PTTestResfileStringWrite (line);

  PTUDFExWriteModelitem (param_owner);
  
  fclose (file_ptr);

  return (PRO_TK_NO_ERROR);
}