/*====================================================================*\
FILE    : TestCabling.c
PURPOSE : Test for Pro/Toolkit cabling functionality 

HISTORY..
   18-AUG-98 I-01-17 Pavel	$$1  Created.
   14-Sep-98 I-01-19 Pavel	$$2  Fixed
   03-Nov-98 I-01-25 Alexey	$$3  Move ProUtilFileOpen() to pt_utils
   29-Dec-98 I-01-28 Alexey	$$4  Add -4 as valid return value to
					TEST_CALL_REPORT for some ProCbl funcs
\*====================================================================*/
#include "prodevelop.h"
#include "pd_prototype.h"

/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include "ProToolkit.h"
#include "ProMessage.h"
#include "ProMenu.h"
#include "ProMessage.h"
#include "ProModelitem.h"
#include "ProSelection.h"
#include "ProUtil.h"

/*--------------------------------------------------------------------*\
Pro/DEVELOP includes
\*--------------------------------------------------------------------*/
#include "profiles.h"

#include "TestError.h"
#include "TestCable.h"
#include "UtilCable.h"
#include "UtilCollect.h"
#include "UtilMenu.h"
#include "UtilMessage.h"
#include "UtilMath.h"
#include "UtilString.h"
/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/
#include <math.h>

/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*\
Application data types
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/
ProCblHarness _harness;
int _is_harness = 0;
ProName _msgfil;

/*--------------------------------------------------------------------*\
Function prototypes
\*--------------------------------------------------------------------*/


/*============================================================================*\
 Function:	user_initialize
 Purpose:       Initialize application
\*============================================================================*/
int user_initialize()
{ 

    int ProTestCabling(), menu_id;
      
    ProTestErrlogOpen("pt_toolkit", "", "");
      
    ProMenuFileRegister("cabling","cabling.mnu", &menu_id);
    ProMenuAuxfileRegister("cabling","cabling.aux", &menu_id);
    ProMenubuttonActionSet("cabling","-Tkcabling",
                        (ProMenubuttonAction)ProTestCabling, NULL, 0);
    return (0);
}


/*============================================================================*\
 Function:	user_terminate
 Purpose:       Close log file. Required function.
\*============================================================================*/
void user_terminate()
{    
    ProTestErrlogClose();
}

/*============================================================================*\
 Function:	ProTestCabling
 Purpose:       Upper level cabling menu
\*============================================================================*/
int ProTestCabling()
{
    ProError	err;
    int		menu_id;
    int		action;
    ProAssembly mdl;	
    
    
    ProStringToWstring(MSGFIL, "cabling_msg.txt");
    err = ProMdlCurrentGet((ProMdl*)&mdl);

    err = ProMenuPush();
    err = ProMenuFileRegister( "TkCabling", "tkcabling.mnu", &menu_id );
    ProMenubuttonActionSet( "TkCabling", "Harness",
        (ProMenubuttonAction)ProTestHarness, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Spools",
        (ProMenubuttonAction)ProTestSpool, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Feature",
        (ProMenubuttonAction)ProTestCable, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Modify",
        (ProMenubuttonAction)ProTestCableModify, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Route",
        (ProMenubuttonAction)ProTestCableRoute, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Components",
        (ProMenubuttonAction)ProTestConnector, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Logical ref",
        (ProMenubuttonAction)ProTestLogicalRef, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Info",
        (ProMenubuttonAction)ProTestCablingInfo, &mdl,  0 );
    ProMenubuttonActionSet( "TkCabling", "Done/Return",
        (ProMenubuttonAction)ProMenuDelete, NULL,  0 );
    ProMenubuttonActionSet( "TkCabling", "TkCabling",
        (ProMenubuttonAction)ProMenuDelete, NULL,  0 );

    err = ProMenuCreate( PROMENUTYPE_MAIN, "TkCabling", &menu_id );
    ProUtilSetCablingMenu();
    if( err == PRO_TK_NO_ERROR )
    {
    	err = ProMenuProcess( "TkCabling", &action );
    	TEST_CALL_REPORT( "ProMenuProcess()", 
			    "ProTestCabling()", err,  err != PRO_TK_NO_ERROR );
    }

    err = ProMenuPop();

    return 0;
}

/*============================================================================*\
 Function:	ProUtilSetCablingMenu
 Purpose:       Enable/Disable TkCabling  menu buttons
\*============================================================================*/
void ProUtilSetCablingMenu()
{
    /* Disable some menu butoons if no current harness available */
    ProUtilMenubuttonActivate("TkCabling", "Feature", IS_CURRENT_HARNESS);
    ProUtilMenubuttonActivate("TkCabling", "Modify", IS_CURRENT_HARNESS);
    ProUtilMenubuttonActivate("TkCabling", "Route", IS_CURRENT_HARNESS);
}


/*============================================================================*\
 Function:	ProTestHarness
 Purpose:       Harness menu
\*============================================================================*/
int ProTestHarness(
    ProAssembly *p_assy)
{
    ProCblHarness *p_harness, harness;
    ProError err;
    int i, n_harness, action, menu_id;
    ProName w_name;
    wchar_t **w_menus;

    err = ProCblAssemblyHarnessesGet(*p_assy, &p_harness, &n_harness);
    TEST_CALL_REPORT( "ProCblAssemblyHarnessesGet()", 
			    "ProTestHarness()", err,  err != PRO_TK_NO_ERROR );
    if ((err != PRO_TK_NO_ERROR) && (err != PRO_TK_E_NOT_FOUND))
	return (0);

    ProUtilMenuStringsAlloc(&w_menus);
    ProUtilMenuStringsStrAdd(&w_menus, "Create");
    for (i=0; i<n_harness; i++)
    {
	err = ProCblHarnessNameGet(p_harness+i, w_name);
	TEST_CALL_REPORT( "ProCblHarnessNameGet()", 
			    "ProTestHarness()", err,  err != PRO_TK_NO_ERROR );

	ProUtilMenuStringsWstrAdd(&w_menus, w_name);
    }

    err = ProUtilMenuStringsIntValueSelect("TkHarnesses", w_menus, &action);
    ProUtilMenuStringsFree(&w_menus);

    if (err != PRO_TK_NO_ERROR)
    {
	ProArrayFree((ProArray*)&p_harness);
	return (0);
    }

    if (action == 0)
    {
	/* Create new harness */
	ProMessageDisplay(MSGFIL, "Test Enter  Part name []:");
	if (ProUtilStringGet(w_name, NULL, PRO_NAME_SIZE))
	{
	    err = ProCblHarnessCreate(*p_assy, w_name, &harness);
	    TEST_CALL_REPORT( "ProCblHarnessCreate()", 
			    "ProTestHarness()", err,  err != PRO_TK_NO_ERROR );
	    if (err == PRO_TK_NO_ERROR)
	    {
		SET_CURRENT_HARNESS(&harness);
		ProUtilSetCablingMenu();
	    }
	}
    }
    else
    {
	SET_CURRENT_HARNESS(&(p_harness[action-1]));
	ProUtilSetCablingMenu();
    }
    if (IS_CURRENT_HARNESS)
    {
	err = ProMenuFileRegister( "TkSubHarness", "tksubharness.mnu", NULL);
	ProMenubuttonActionSet( "TkSubHarness", "Show Cables",
	    (ProMenubuttonAction)ProTestHarnessCablesAction, p_assy, 
	    TEST_CABLES_SHOW);
	ProMenubuttonActionSet( "TkSubHarness", "TkSubHarness",
	    (ProMenubuttonAction)ProMenuDelete, NULL,  0);

	err = ProMenuCreate( PROMENUTYPE_MAIN, "TkSubHarness", &menu_id );

	if( err == PRO_TK_NO_ERROR )
	{
    	    err = ProMenuProcess( "TkSubHarness", &action );
    	    TEST_CALL_REPORT( "ProMenuProcess()", 
				"ProTestCabling()", err,  err != PRO_TK_NO_ERROR );
	}
    }
    ProUtilSetCablingMenu();
    return (0);
}

/*============================================================================*\
 Function:	ProUtilFindAssmeblyHarness
 Purpose:       Set up asmcomppath for harness
\*============================================================================*/
ProError ProUtilFindAssmeblyHarness(
    ProAssembly assy,
    ProPart harness,
    ProAsmcomppath *p_path)
{
    ProError err;
    ProIdTable memb_id_tab;
    ProAsmcomp *p_comps;
    int i, n_comps;
    ProMdl mdl;

    err = ProUtilCollectAsmcomp(assy, &p_comps);
    if (err  != PRO_TK_NO_ERROR)
	return (err);
    err = ProArraySizeGet(p_comps, &n_comps);
    for (i=0; i<n_comps; i++)
    {
	ProAsmcompMdlGet(p_comps+i, &mdl);
	if (mdl == (ProMdl)harness)
	{
	    memb_id_tab[0] = p_comps[i].id;
	    memb_id_tab[1] = -1;
	    ProAsmcomppathInit((ProSolid)assy, memb_id_tab, 2, p_path);
	    ProArrayFree((ProArray*)&p_comps);
	    return (PRO_TK_NO_ERROR);
	}
    }
    ProArrayFree((ProArray*)&p_comps);
    return (PRO_TK_GENERAL_ERROR);
}


/*============================================================================*\
 Function:	ProTestHarnessCablesAction
 Purpose:       Show harness cables
\*============================================================================*/
int ProTestHarnessCablesAction(
    ProAssembly *p_assy,
    int		action)
{

    ProError err;
    ProCblCable *p_cables;
    int i, n_cables, id;
    ProSelection selection;
    ProAsmcomppath harness_path;
    ProModelitem modelitem;
    

    switch (action)
    {
    case  TEST_CABLES_SHOW:
	err = ProUtilFindAssmeblyHarness(*p_assy, _harness.harness,
	    &harness_path);
	harness_path.table_num = 1;

	err = ProCblHarnessCablesGet(&_harness, &p_cables, &n_cables);
	TEST_CALL_REPORT( "ProCblHarnessCablesGet()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );
	for (i=0; i<n_cables; i++)
	{
	    err = ProCblCableIdGet(p_cables+i, &id);
	    TEST_CALL_REPORT( "ProCblCableIdGet()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );

	    /* Cables really features in harness */
	    err = ProModelitemInit((ProMdl*)_harness.harness, id, PRO_FEATURE,
		&modelitem);
	    TEST_CALL_REPORT( "ProModelitemInit()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );
	    err = ProSelectionAlloc(&harness_path, &modelitem, &selection);
	    TEST_CALL_REPORT( "ProSelectionAlloc()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );
	    err = ProSelectionHighlight(selection, PRO_COLOR_HIGHLITE);
	    TEST_CALL_REPORT( "ProSelectionHighlight()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );
	    err = ProSelectionFree(&selection);
	    TEST_CALL_REPORT( "ProSelectionFree()", 
		"ProTestHarnessCablesAction()", err,  err != PRO_TK_NO_ERROR );
	}
	break;
    }
    return (0);
}


/*============================================================================*\
 Function:  ProUtilParametersFileWrite
 Purpose:       
\*============================================================================*/
ProError ProUtilParametersFileWrite(
    FILE *file,
    ProCblParameterInfo *p_param,
    int n_param)
{
    int i, j;
    ProCblParameterInfo *p_params;
    ProCharName name, name2;
    ProCharLine line;

    for (i=0; i<n_param; i++)
    {
        ProWstringToString(name, p_param[i].name);
        fprintf(file, "!%-31s", name);
        if  (p_param[i].value_type == PRO_MULTICELL_TYPE)
            for (j=0; j<p_param[i].value.multval.ncells; j++)
            {
                ProWstringToString(name2,
                    p_param[i].value.multval.cells[j].name);
                fprintf(file, "%-32s", name2);
            }
        fprintf(file, "\n%-32s", name);
        switch (p_param[i].value_type)
        {
        case PRO_INTEGER_TYPE:             
             fprintf(file, "%-32d\n", p_param[i].value.intval);
             break;
        case PRO_DOUBLE_TYPE:
             fprintf(file, "%-32.3f\n",  p_param[i].value.dblval);
             break;
        case PRO_WIDE_STRING_TYPE:
             ProWstringToString(line, p_param[i].value.strval);
             fprintf(file, "%-32s\n", line);
             break;
        case PRO_MULTICELL_TYPE:
             for (j=0; j<p_param[i].value.multval.ncells; j++)
             {
                 p_params = p_param[i].value.multval.cells + j;
                 switch (p_params->value_type)  
                 {
                 case PRO_INTEGER_TYPE:             
                     fprintf(file, "%-32d", p_params->value.intval);
                     break;
                 case PRO_DOUBLE_TYPE:
                     fprintf(file, "%-32.3f",  p_params->value.dblval);
                     break;
                 case PRO_WIDE_STRING_TYPE:
                     ProWstringToString(line, p_params->value.strval);
                     fprintf(file, "%-32s", line);
                     break;
                 }
                
             }
             fprintf(file, "\n"); 
             break;
        }
    }
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:  ProUtilTokenToParamValue
 Purpose:   converts token to param value and returns its type    
\*============================================================================*/
int ProUtilTokenToParamValue(
    char* token,
    void* param_value)
{
    double d, *p_d;
    char *end_ptr;
    int i, *p_i;

    d = strtod(token, &end_ptr);
    if (end_ptr[0] == '\0' )
    {
	/* Value double or integer */
	i = (int)d;
	if (fabs(i-d) < EPSM6)
	{
	    p_i = (int*)param_value;
	    *p_i = i;
	    return (PRO_INTEGER_TYPE);
	}
	else
	{
	    p_d = (double*)param_value;
	    *p_d = d;
	    return (PRO_DOUBLE_TYPE);
	}
    }
    else
    {
	ProStringToWstring((wchar_t*)param_value, token);
	return (PRO_WIDE_STRING_TYPE);
    }
}

/*============================================================================*\
 Function:  ProUtilParametersFileRead
 Purpose:   Read parameter file saved by ProUtilParametersFileWrite
\*============================================================================*/
ProError ProUtilParametersFileRead(
    char *filename,
    ProCblParameterInfo **pp_param,
    int *pn_param)
{
    FILE *file;
    char last_line[PRO_PATH_SIZE], line[PRO_PATH_SIZE];
    char *tokens[TEST_MAX_TOKENS], *names[TEST_MAX_TOKENS];
    ProCblParameterInfo *p_param, param, param2;
    int i, n_param = 0, n_cells;

    file = fopen(filename, "r");
    if (file == NULL)
	return (PRO_TK_GENERAL_ERROR);

    ProArrayAlloc(0, sizeof(ProCblParameterInfo), 1, (ProArray*)&p_param);
    while ((!feof(file)) && (fgets(line, PRO_PATH_SIZE, file) != NULL))
    {
	if (line[0] == '!')
	{
	    /* Read comment / The parameters name line */
	    strcpy(last_line, line);
	    continue;
	}
	
	tokens[0] = strtok(line, " \t\n");
	i = 0;
	/* While there are tokens in "string" */
	while( tokens[i] != NULL )
	{
	    i++;
	    if (i>= TEST_MAX_TOKEN)
		break;
	    /* Get next token: */
	    tokens[i] = strtok(NULL, " \t\n");
	}
	/*Invalid string */
	if (i <2)
	    continue;
	if (i == 2)
	{
	    /* Found simple parameter */
	    ProStringToWstring(param.name, tokens[0]);
	    param.param_type = PRO_USER_PARAM;
	    param.value_type = ProUtilTokenToParamValue(tokens[1], &param.value);
	    ProArrayObjectAdd((ProArray*)&p_param, -1, 1, &param);
	    n_param++;
	}
	else
	{
	    /* Found multicell parameter */
	    n_cells = i;
	    names[0] = strtok(last_line, " \t\n");
	    i = 0;
	    /* While there are names in "string" */
	    while( names[i] != NULL )
	    {
		i++;
		if (i>= TEST_MAX_TOKEN)
		    break;
		/* Get next token: */
		names[i] = strtok(NULL, " \t\n");
	    }
	    /* Skip if two lines have different numbers of tokens */
	    if (i != n_cells)
		continue;
	    ProStringToWstring(param.name, tokens[0]);
	    param.param_type = PRO_USER_PARAM;
	    param.value_type = PRO_MULTICELL_TYPE;
	    ProArrayAlloc(0, sizeof(param), 1, 
		(ProArray*)&param.value.multval.cells);
	    param.value.multval.ncells = n_cells - 1;

	    for (i=1; i<n_cells; i++)
	    {
		ProStringToWstring(param2.name, names[i]);
		param2.param_type = PRO_USER_PARAM;
		param2.value_type = ProUtilTokenToParamValue(tokens[i],
		    &param2.value);
		ProArrayObjectAdd((ProArray*)&param.value.multval.cells, -1, 1, 
		    &param2);
	    }
	    ProArrayObjectAdd((ProArray*)&p_param, -1, 1, &param);
	    n_param++;
	}
    }

    *pp_param = p_param;
    *pn_param = n_param;
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:  ProUtilParametersFree
 Purpose:   Free memo
\*============================================================================*/
ProError ProUtilParametersFree(
    ProCblParameterInfo **pp_param,
    int n_param)
{
    int i;

    for (i=0; i<n_param; i++)
	if (pp_param[0][i].value_type == PRO_MULTICELL_TYPE)
	    ProArrayFree((ProArray*)&pp_param[0][i].value.multval.cells);
    ProArrayFree((ProArray*)pp_param);
    return (PRO_TK_NO_ERROR);
}


/*============================================================================*\
 Function:  ProTestCablingInfo
 Purpose:   Cable info menu
\*============================================================================*/
int ProTestCablingInfo(
    ProAssembly *p_assy)
{
    ProError err;
    int menu_id, action;
    
    err = ProMenuFileRegister( "TkCabling Info", "tkcablinginfo.mnu", &menu_id );
    ProMenubuttonActionSet( "TkCabling Info", "Harness Items",
	(ProMenubuttonAction)ProTestCablingInfoAction, p_assy, 
	TEST_HARNESS_ITEMS);
    ProMenubuttonActionSet( "TkCabling Info", "Harness Wirelist",
	(ProMenubuttonAction)ProTestCablingInfoAction, p_assy, 
	TEST_HARNESS_WIRELIST);
    ProMenubuttonActionSet( "TkCabling Info", "Phisical Routing",
	(ProMenubuttonAction)ProTestCablingInfoAction, p_assy, 
	TEST_HARNESS_ROUTING);
    ProMenubuttonActionSet( "TkCabling Info", "TkCabling Info",
	(ProMenubuttonAction)ProMenuDelete, NULL, 0);
    err = ProMenubuttonDelete("TkCabling Info", "Phisical Routing", &action);
    err = ProMenuCreate( PROMENUTYPE_MAIN, "TkCabling Info", &menu_id );
    err = ProMenuProcess( "TkCabling Info", &action );
    TEST_CALL_REPORT( "ProMenuProcess()", 
			"ProTestCable()", err,  err != PRO_TK_NO_ERROR );       
    return (0);
}


/*============================================================================*\
 Function:  ProTestCablingInfoAction
 Purpose:   Cable info action
\*============================================================================*/
int ProTestCablingInfoAction(
    ProAssembly *p_assy,
    int action)
{
    FILE *file;
    ProCblHarness *p_harness;
    int n_harness, i, n_cable, j, has_spool;
    ProCharName name;
    ProCblCable *p_cables;
    ProName w_filename;
    ProError err;

    switch (action)
    {
    case TEST_HARNESS_ITEMS:
    case TEST_HARNESS_WIRELIST:
	file = fopen("cables.inf", "w");

	err = ProCblAssemblyHarnessesGet (*p_assy, &p_harness, &n_harness);
	TEST_CALL_REPORT( "ProCblAssemblyHarnessesGet()", 
		"ProTestCablingInfoAction()", err,  err != PRO_TK_NO_ERROR );
	for (i=0; i<n_harness; i++)
	{
	    ProWstringToString(name, p_harness[i].name);
	    fprintf(file, "HARNESS NAME: %s\n\n", name);
		
	    err = ProCblHarnessCablesGet(p_harness + i , &p_cables, &n_cable);
	    TEST_CALL_REPORT( "ProCblHarnessCablesGet()", 
		"ProTestCablingInfoAction()", err,  err != PRO_TK_NO_ERROR );

	    if (action == TEST_HARNESS_WIRELIST)
		fprintf(file, "Cable name      Cnd Color   Length    "
		    "From                    To\n");

	    for (j=0; j<n_cable; j++)
    	    {
		err = ProTestCablingInfoCableWrite(file, *p_assy, p_cables+j,
		    action);
	    }
	}
	fclose (file);
	ProStringToWstring(w_filename, "cables.inf");
	err = ProInfoWindowDisplay(w_filename, NULL, NULL);
    }
    return (0);
}

/*============================================================================*\
 Function:  ProTestCablingInfoCableWrite
 Purpose:   Write parameters into file
\*============================================================================*/
ProError ProTestCablingInfoCableWrite(
    FILE *file,
    ProAssembly assy,
    ProCblCable *p_cable,
    int action)
{

    ProCblParameterInfo param;
    ProName w_name, w_param_name, w_names[2], w_ports[2];
    ProCharName name, param_value, names[2], str_color, str_len;
    ProCblSpool spool;
    ProError err;
    ProBoolean incomplete;
    Select3d connectors[2];
    ProModelitem modelitem;
    double length = 0.0;
    int i, has_spool;
    Procbl_cable_type cable_type;
    ProAsmcomppath path;
    ProCblConnector connector;

    /* Get cable name */
    err = ProCblCableNameGet(p_cable, w_name);
    TEST_CALL_REPORT( "ProCblCableNameGet()", 
		"ProTestCablingInfoCableWrite()", err, err != PRO_TK_NO_ERROR);
    ProWstringToString(name, w_name);

    /* Find cable logical ends */
    err = ProCblCableLogicalEndsGet(p_cable, connectors);
    TEST_CALL_REPORT( "ProCblCableLogicalEndsGet()", 
	"ProTestCablingInfoCableWrite()", 
	err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
    if (err == PRO_TK_NO_ERROR)
    {
	incomplete = PRO_B_FALSE;
	for (i=0; i<2; i++)
	{
	    err = ProModelitemInit((ProMdl)connectors[i].part_ptr, 
		connectors[i].selected_id, PRO_CSYS, &modelitem);
	    err = ProModelitemNameGet(&modelitem, w_ports[i]);

	    err = ProAsmcomppathInit((ProSolid)connectors[i].assembly_ptr,
		connectors[i].memb_id_tab, connectors[i].memb_num, &path);
	    err = ProCblConnectorInit(&path, &connector);
	    TEST_CALL_REPORT( "ProCblConnectorInit()", 
		"ProTestCablingInfoCableWrite()", 
		err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
	    ProStringToWstring(w_param_name, "REF_DES");
	    err = ProCblConnectorParameterGet(&connector, w_param_name, &param);
	    TEST_CALL_REPORT( "ProCblConnectorParameterGet()", 
		"ProTestCablingInfoCableWrite()", err, err != PRO_TK_NO_ERROR);
	    ProWstringToString(names[i], param.value.strval);
	}
    }
    else
    {
	incomplete = PRO_B_TRUE;
	names[0][0]= '\0';
	names[1][0]= '\0';
    }

    err = ProCblCableLengthGet(p_cable, &length);
    TEST_CALL_REPORT( "ProCblCableLengthGet()", 
	    "ProTestCablingInfoCableWrite()", err, 0);

    /* Find cable spool */
    ProStringToWstring(w_param_name, "SPOOL");
    err = ProCblCableParameterGet(p_cable, w_param_name, &param);
    TEST_CALL_REPORT( "ProCblCableParameterGet()", 
	"ProTestCablingInfoCableWrite()", 
	err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
    
    has_spool = err == PRO_TK_NO_ERROR;
    if (has_spool)
    {
        err = ProCblSpoolInit(assy, param.value.strval, &spool);
        TEST_CALL_REPORT( "ProCblSpoolInit()", 
	    "ProTestCablingInfoCableWrite()", err, err != PRO_TK_NO_ERROR);
    }
    if (action == TEST_HARNESS_ITEMS)
    {
	fprintf(file, "CABLE NAME: %s\n", name);
	if (err == PRO_TK_NO_ERROR)
	{
	    ProWstringToString(param_value, param.value.strval);
	    fprintf(file, "SPOOL NAME: %s\n", param_value);
	}
	if (incomplete == PRO_B_FALSE)
	{
	    fprintf(file, "CONNECTOR NAMES:\n");
	    for (i=0; i<2; i++)
	    {
		ProWstringToString(name, w_ports[i]);
		fprintf(file, "\t%s (Entry port name: %s)\n", names[i], 
		    name);
	    }
	}

        if (has_spool)
        {
	    ProStringToWstring(w_param_name, "MIN_BEND_RADIUS");
	    err = ProCblSpoolParameterGet(&spool, w_param_name, &param);
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
		"ProTestCablingInfoCableWrite()", 
		err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
	    if (err == PRO_TK_NO_ERROR)
	    {
	        fprintf(file, "MINIMUM BEND RADIUS = %.4f\n", param.value.dblval);
	    }
	    ProStringToWstring(w_param_name, "THICKNESS");
	    err = ProCblSpoolParameterGet(&spool, w_param_name, &param);
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
		"ProTestCablingInfoCableWrite()", 
		err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
	    if (err == PRO_TK_NO_ERROR)
	    {
	        fprintf(file, "THICKNESS = %.4f\n", param.value.dblval);
	    }
	    ProStringToWstring(w_param_name, "DENSITY");
	    err = ProCblSpoolParameterGet(&spool, w_param_name, &param);
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
		"ProTestCablingInfoCableWrite()", 
		err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND);
	    if (err != PRO_TK_NO_ERROR)
	        param.value.dblval = 0;
	    fprintf(file, "DENSITY = %.4f\n", param.value.dblval);
        }
	if (incomplete == PRO_B_TRUE)
	{
	    fprintf(file, "\nWARNING: Cable is incomplete.\n");
	}
	fprintf(file, "\n");    
    }
    else
    {
	err = ProCblCableTypeGet(p_cable, &cable_type);
	TEST_CALL_REPORT( "ProCblCableTypeGet()", 
	    	"ProTestCablingInfoCableWrite()", err, err != PRO_TK_NO_ERROR);
	if (cable_type != PROCBL_TYPE_WIRE)
	{
	    strcpy(str_color, "---");
	}
	else
	{
	    ProStringToWstring(w_param_name, "COLOR");
	    err = ProCblSpoolParameterGet(&spool, w_param_name, &param);
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
	    	"ProTestCablingInfoCableWrite()", 
		err, err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND);
	    if (err == PRO_TK_NO_ERROR)
		ProWstringToString(str_color, param.value.strval);
	    else
		str_color[0] = '\0';
	}

	if (length == 0.0)
	    str_len[0] = '\0';
	else
	    sprintf(str_len, "%.3f", length);
	fprintf(file, "%-16s%-12s%-10s%-25s%s\n",
	    name, str_color, str_len, names[0], names[1]); 
    }
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:	ProTestLogicalRef
 Purpose:       Test logical ref functions menu
\*============================================================================*/
int ProTestLogicalRef(
    ProAssembly *p_assy)
{
    ProError err;
    int action, menu_id;

    err = ProMenuPush();
    err = ProMenuFileRegister( "TkLogical Ref", "tklogref.mnu", &menu_id );
    ProMenubuttonActionSet( "TkLogical Ref", "Import",
        (ProMenubuttonAction)ProTestLogicalRefImport, p_assy,  0 );
    ProMenubuttonActionSet( "TkLogical Ref", "Done/Return",
        (ProMenubuttonAction)ProMenuDelete, NULL,  0 );
    ProMenubuttonActionSet( "TkLogical Ref", "TkLogical Ref",
        (ProMenubuttonAction)ProMenuDelete, NULL,  0 );

    err = ProMenuCreate( PROMENUTYPE_MAIN, "TkLogical Ref", &menu_id );
    err = ProMenuProcess( "TkLogical Ref", &action );
    TEST_CALL_REPORT( "ProMenuProcess()", 
			"ProTestLogicalRef()", err,  err != PRO_TK_NO_ERROR );

    err = ProMenuPop();
    return (0);
}

/*============================================================================*\
 Function:	ProTestLogicalRefImport
 Purpose:       Import logical ref from Mentor graph file
\*============================================================================*/
int ProTestLogicalRefImport(
    ProAssembly *p_assy)
{
    ProError err;
    ProName w_name;

    err = ProMessageDisplay(MSGFIL, 
	"TEST Enter file name to read Mentor wire list from [Quit]:");

    err = ProMessageStringRead(PRO_NAME_SIZE, w_name);
    if (err != PRO_TK_NO_ERROR)
	return (0);

    err = ProInputFileRead((ProMdl)*p_assy, w_name, 
	PRO_WIRELIST_FILE, NULL, NULL, NULL, NULL);
    TEST_CALL_REPORT( "ProInputFileRead()", 
		  "ProTestLogicalRefImport()", err,  err != PRO_TK_NO_ERROR );
    if (err == PRO_TK_NO_ERROR)
    {
	ProMessageDisplay(MSGFIL, "TEST File containing "
		    "Mentor Graphics wirelist has been read successfully.");
    }
    return (0);
}




/*============================================================================*\
 Function:  ProUtilParametersMenu
 Purpose:   connector's parameters menu
\*============================================================================*/
int ProUtilParametersMenu(
    TestParamOwner *p_owner)
{
    ProError err;
    int menu_id, action;

    err = ProMenuFileRegister( "TkParameters", "tkparameters.mnu", &menu_id );
    ProMenubuttonActionSet( "TkParameters", "Retrieve",
	(ProMenubuttonAction)ProUtilParametersAction, p_owner,
	TEST_PARAM_RETR);
    ProMenubuttonActionSet( "TkParameters", "Save",
	(ProMenubuttonAction)ProUtilParametersAction, p_owner,
	TEST_PARAM_SAVE);
    ProMenubuttonActionSet( "TkParameters", "Mod Params",
	(ProMenubuttonAction)ProUtilParametersAction, p_owner,
	TEST_PARAM_MOD);
    ProMenubuttonActionSet( "TkParameters", "Show",
	(ProMenubuttonAction)ProUtilParametersAction, p_owner,
	TEST_PARAM_SHOW);
    ProMenubuttonActionSet( "TkParameters", "Done/Return",
	(ProMenubuttonAction)ProMenuDelete, NULL, 0);
    ProMenubuttonActionSet( "TkParameters", "TkParameters",
	(ProMenubuttonAction)ProMenuDelete, NULL, 0);
    err = ProMenuCreate( PROMENUTYPE_MAIN, "TkParameters", &menu_id );

    err = ProMenuProcess( "TkParameters", &action );
    TEST_CALL_REPORT( "ProMenuProcess()", 
		"ProTestConnectorAction()", err,  err != PRO_TK_NO_ERROR );
    return (0);
}


/*============================================================================*\
 Function:  ProUtilParametersAction
 Purpose:   Modify connector/cable parameters
\*============================================================================*/
int ProUtilParametersAction(
    TestParamOwner *p_owner,
    int action)
{
    ProError err;
    ProCblParameterInfo *p_param = NULL;
    int n_param;
    ProLine w_file_name;
    ProCharLine file_name;
    FILE *file;

    switch (action)
    {
    case TEST_PARAM_SAVE:
    case TEST_PARAM_SAVE_DEFAULT:
	if (action != TEST_PARAM_SAVE_DEFAULT)
	{
	    ProMessageDisplay(MSGFIL, 
		"TEST Enter file name to write parameters to [QUIT]:");
	    err = ProMessageStringRead(PRO_NAME_SIZE, w_file_name);
	    if (err != PRO_TK_NO_ERROR)
		return (0);
	    ProWstringToString(file_name, w_file_name);
	    if (strchr(file_name, '.') == NULL)
		strcat(file_name, p_owner->owner_type ? ".con" : ".cbl");
	}
	else
	{
	    strcpy(file_name, TEMP_FILE);
	}
	
	if (p_owner->owner_type)
	{
	    err = ProCblConnectorParametersGet(
		(ProCblConnector*)p_owner->param_owner, &p_param, &n_param);
	    TEST_CALL_REPORT( "ProCblConnectorParametersGet()", 
		"ProUtilParametersAction()", err,  err != PRO_TK_NO_ERROR);
	}
	else
	{
	    err = ProCblCableParametersGet(
		(ProCblCable*)p_owner->param_owner, &p_param, &n_param);
	    TEST_CALL_REPORT( "ProCblCableParametersGet()", 
		"ProUtilParametersAction()", err,  err != PRO_TK_NO_ERROR);
	}

	file = fopen(file_name, "w");
	fprintf(file, "! Enter or modify parameters for the %s.\n",
	    p_owner->owner_type ? "connector" : "cable");
	ProUtilParametersFileWrite(file, p_param, n_param);
	fclose(file);
	if (action == TEST_PARAM_SAVE)
	    ProMessageDisplay(MSGFIL, 
	    "TEST Parameter file %0s was created successfully.", file_name);
	break;
    case TEST_PARAM_MOD:
	ProUtilParametersAction(p_owner, TEST_PARAM_SAVE_DEFAULT);
        ProStringToWstring(w_file_name, TEMP_FILE);
        ProFileEdit(w_file_name);
 	ProUtilParametersRead(p_owner, TEMP_FILE);
	break;	
    case TEST_PARAM_RETR:
	err = ProUtilFileOpen(p_owner->owner_type ? "*.con" : "*.cbl", 
	    file_name);
	if (err != PRO_TK_NO_ERROR)
	    break;
	ProUtilParametersRead(p_owner, file_name);
	break;
    case TEST_PARAM_SHOW:
        ProUtilParametersAction(p_owner, TEST_PARAM_SAVE_DEFAULT);
        ProStringToWstring(w_file_name, TEMP_FILE);
        ProInfoWindowDisplay(w_file_name, NULL, NULL);
        break;       
   }
   return(0);

}

/*============================================================================*\
 Function:  ProUtilParametersRead
 Purpose:   Read connector's parameters from file
\*============================================================================*/
ProError ProUtilParametersRead(
    TestParamOwner *p_owner,
    char    *file_name)
{      
    ProError err;
    ProCblParameterInfo *p_param, *p_param2;
    int n_param, n_param2, i, j;
    
    if (p_owner->owner_type)
    {
	err = ProCblConnectorParametersGet(
	    (ProCblConnector*)p_owner->param_owner, &p_param, &n_param);
	TEST_CALL_REPORT( "ProCblConnectorParametersGet()", 
	    "ProTestConnParametersRead()", err,  err != PRO_TK_NO_ERROR );
    }
    else
    {
	err = ProCblCableParametersGet(
	    (ProCblCable*)p_owner->param_owner, &p_param, &n_param);
	TEST_CALL_REPORT( "ProCblCableParametersGet()", 
	    "ProTestConnParametersRead()", err,  err != PRO_TK_NO_ERROR );
    }

    if (err != PRO_TK_NO_ERROR)
        return (err);
    err = ProUtilParametersFileRead(file_name, &p_param2, &n_param2);

    /* First delete parameters which are not present in new file */
    for (i=0; i<n_param; i++)
    {
	for (j=0; j<n_param2; j++)
	    if (!ProUtilWstrcmp(p_param[i].name, p_param2[j].name))
		break;
	if (j<n_param2)
	    continue;
	/* Parameter was not found anymore - will be deleted */
	if (p_owner->owner_type)
	{
	    err = ProCblConnectorParameterDelete(
		(ProCblConnector*)p_owner->param_owner, p_param[i].name);
	    TEST_CALL_REPORT("ProCblConnectorParameterDelete()",
		"ProTestConnParametersRead()", err, err != PRO_TK_NO_ERROR);
	}
	else
	{
	    err = ProCblCableParameterDelete(
		(ProCblCable*)p_owner->param_owner, p_param[i].name);
	    TEST_CALL_REPORT("ProCblCableParameterDelete()",
		"ProTestConnParametersRead()", err, err != PRO_TK_NO_ERROR);
	}
    }

    /* setup new parameter name */
    if (p_owner->owner_type)
    {
	err = ProCblConnectorParametersSet (
	    (ProCblConnector*)p_owner->param_owner, p_param2, n_param2);
	TEST_CALL_REPORT("ProCblConnectorParametersSet()",
	    "ProTestConnParametersRead()", err,  err != PRO_TK_NO_ERROR );
    }
    else
    {
	err = ProCblCableParametersSet (
	    (ProCblCable*)p_owner->param_owner, p_param2, n_param2);
	TEST_CALL_REPORT("ProCblCableParametersSet()",
	    "ProTestConnParametersRead()", err,  err != PRO_TK_NO_ERROR );
    }
    ProUtilParametersFree(&p_param2, n_param2);
    return (PRO_TK_NO_ERROR);
}


/*=============================================================*\
  Function:	ProTestCableRoute
  Purpose:	route cable (s)
\*=============================================================*/
int ProTestCableRoute (
	ProAssembly *p_assy) 
{
    int  ierr, i, menu_id, action;
    void *routing_data;
    Select3d *sel;
    ProCblCable *p_cables, cable;
    ProError err;

/*----------------------------------------------------------------*\
    procbl_get_harness_cables
\*----------------------------------------------------------------*/
    ierr = pro_select("cable", -1, &sel,
	ProTestCurrentHarnessPreFilter, NULL);
    if (ierr <= 0)
	return (-1);
    ProArrayAlloc(0, sizeof(ProCblCable), 1, (ProArray*)&p_cables);
    for (i=0; i<ierr; i++)
    {
	err = ProCblCableInit(sel[i].selected_id, NULL, &_harness,
	    &cable);
	TEST_CALL_REPORT("ProCblCableInit()",
		    "TestCableRoute()", err,  err != PRO_TK_NO_ERROR );
	if (err == PRO_TK_NO_ERROR)
	    err = ProArrayObjectAdd((ProArray*)&p_cables, -1, 1,
		&cable); 
    }
/*----------------------------------------------------------------*\
    Start routing
\*----------------------------------------------------------------*/
    err = ProCblRoutingStart(p_cables, &routing_data);
    TEST_CALL_REPORT("ProCblRoutingStart()",
		    "TestCableRoute()", err,  err != PRO_TK_NO_ERROR );

    ProMenuFileRegister("TkCbl Route", "tkcblroute.mnu", &menu_id);
    ProMenubuttonActionSet("TkCbl Route", "connector",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, PROLOC_TYPE_CONNECTOR);
    ProMenubuttonActionSet("TkCbl Route", "point",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, PROLOC_TYPE_POINT);
    ProMenubuttonActionSet("TkCbl Route", "axis",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, PROLOC_TYPE_AXIS);
    ProMenubuttonActionSet("TkCbl Route", "offset",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, PROLOC_TYPE_OFFSET);
    ProMenubuttonActionSet("TkCbl Route", "location",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, PROLOC_TYPE_LOC);
    ProMenubuttonActionSet("TkCbl Route", "Done Route",
	(ProMenubuttonAction)ProTestSelLoc, &routing_data, -1);
    ProMenubuttonActionSet("TkCbl Route", "TkCbl Route",
	(ProMenubuttonAction)ProMenuDelete, NULL, 0);

    err = ProMenuCreate( PROMENUTYPE_MAIN, "TkCbl Route", &menu_id );
    err = ProMenuProcess( "TkCbl Route", &action );
   
    err = ProSolidRegenerate(*p_assy, PRO_B_FALSE);
    err = ProWindowRepaint(PRO_VALUE_UNUSED);
    
    return (0);
}


/*=============================================================*\
  Function:	ProTestSelLoc
  Purpose:	return selected location value
\*=============================================================*/
int ProTestSelLoc(void **routing_data, int type)
{
    ProCblLocRef locref;
    Select3d *sel;
    int *locs, n_locs;
    ProError err;

    switch(type)
    {
    case PROLOC_TYPE_CONNECTOR :
	ProMessageDisplay(MSGFIL, "TEST Select entry port.");
	if (pro_select("csys", 1, &sel, NULL, NULL) < 0)  return(0);
	break;

    case PROLOC_TYPE_POINT :
	ProMessageDisplay(MSGFIL, "TEST Select point.");
	if (pro_select("point", 1, &sel, NULL, NULL) < 0)  return(0);
	break;

    case PROLOC_TYPE_AXIS :
	ProMessageDisplay(MSGFIL, "TEST Select axis.");
	if (pro_select("axis", 1, &sel, NULL, NULL) < 0) return(0);
	locref.axis_flip = 0;
	break;

    case PROLOC_TYPE_OFFSET :
	ProMessageDisplay(MSGFIL, "TEST Select csys.");
	if (pro_select("csys", 1, &sel, NULL, NULL) < 0) return(0);

	ProMessageDisplay(MSGFIL, "TEST Enter X offset value [0.0] :");
	if (ProMessageDoubleRead(NULL, &locref.x_offset)) locref.x_offset = 0.0;

	ProMessageDisplay(MSGFIL, "TEST Enter Y offset value [0.0] :");
	if (ProMessageDoubleRead(NULL, &locref.y_offset)) locref.y_offset = 0.0;

	ProMessageDisplay(MSGFIL, "TEST Enter Z offset value [0.0] :");
	if (ProMessageDoubleRead(NULL, &locref.z_offset)) locref.z_offset = 0.0;
	break;

    case PROLOC_TYPE_LOC :
	ProMessageDisplay(MSGFIL, "TEST Select a location.");
	if(pro_select("location", 1, &sel, NULL, NULL) < 0) return(0);
	break;

    case -1:
/*----------------------------------------------------------------*\
    Routing end
\*----------------------------------------------------------------*/
	err = ProCblRoutingEnd (routing_data);
	TEST_CALL_REPORT("ProCblRoutingEnd()",
			    "ProTestSelLoc()", err,  err != PRO_TK_NO_ERROR );

	ProMessageDisplay(MSGFIL, "TEST Routing ended successfully.");
	ProMenuDeleteWithStatus(1);

	return(0);
    }

    locref.refs = (Select3d**)calloc(1, sizeof(Select3d*));
    locref.refs[0] = sel;
    locref.type = type;		/*  Set the type here  */
    locref.num_refs = 1;

/*----------------------------------------------------------------*\
    procbl_route_thru_location
\*----------------------------------------------------------------*/
    err = ProCblRouteThruLocation(*routing_data, &locref, &locs, &n_locs);
    TEST_CALL_REPORT("ProCblRouteThruLocation()",
			    "ProTestSelLoc()", err,  err != PRO_TK_NO_ERROR );

    free(locref.refs);

    return (0);
}
