/*================================================================*\
    FILE:       TestSpool.c
    PURPOSE:    Functions to manage cabling

    HISTORY:
   18-AUG-98 I-01-17 Pavel    $$1  Created.
   14-Sep-98 I-01-19 Pavel    $$2  Fixed
   29-Dec-98 I-01-28 Alexey   $$3  Add -4 as valid return value to 
				   TEST_CALL_REPORT for some ProCbl funcs
\*=================================================================*/

#include "UtilCable.h"

#include "UtilString.h"
#include "TestError.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 "UtilMenu.h"
#include "UtilMessage.h"
#include "UtilMath.h"
#include "UtilString.h"
/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/
#include <math.h>

/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
#define MSGFIL _msgfil

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

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Function prototypes
\*--------------------------------------------------------------------*/
int ProTestSpool(ProAssembly*);
int ProTestSpoolAction(ProAssembly*, int action);
ProError ProTestSpoolParametersEdit(ProCblSpool*spool);

ProError ProUtilParametersFileWrite(FILE *file, ProCblParameterInfo *p_param,
    int n_param);
ProError ProUtilParametersFileRead(char *filename, ProCblParameterInfo **pp_param,
    int *pn_param);
ProError ProUtilSpoolParametersToSpoolType(ProCblParameterInfo **pp_param,
    int *pn_param, ProName name, Procbl_cable_type *p_cable_type, 
    Procbl_sheath_type *p_sheath_type);
ProError ProUtilParametersFree(ProCblParameterInfo **pp_param, int n_param);
ProError ProUtilFileOpen(char *extension,char *file_name);
void ProUtilSetSpoolMenu(ProAssembly *p_assy);


/*============================================================================*\
 Function:	ProTestSpool
 Purpose:       Upper level spool menu
\*============================================================================*/
int ProTestSpool(
    ProAssembly *p_assy)
{
    ProError	err;
    int		menu_id, action, n_spools = 0;
    
    err = ProMenuFileRegister( "TkSpool", "tkspool.mnu", &menu_id );
    ProMenubuttonActionSet( "TkSpool", "Read",
        (ProMenubuttonAction)ProTestSpoolAction, p_assy,  TEST_SPOOL_READ );
    ProMenubuttonActionSet( "TkSpool", "Write",
        (ProMenubuttonAction)ProTestSpoolAction, p_assy,  TEST_SPOOL_WRITE );
    ProMenubuttonActionSet( "TkSpool", "Create",
        (ProMenubuttonAction)ProTestSpoolAction, p_assy,  TEST_SPOOL_CREATE );
    ProMenubuttonActionSet( "TkSpool", "Edit",
        (ProMenubuttonAction)ProTestSpoolAction, p_assy,  TEST_SPOOL_EDIT );
    ProMenubuttonActionSet( "TkSpool", "List",
        (ProMenubuttonAction)ProTestSpoolAction, p_assy,  TEST_SPOOL_LIST );
    ProMenubuttonActionSet( "TkSpool", "TkSpool",
        (ProMenubuttonAction)ProMenuDelete, NULL,  0 );

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

    ProUtilSetSpoolMenu(p_assy);
        
    err = ProMenuProcess( "TkSpool", &action );
    TEST_CALL_REPORT( "ProMenuProcess()", 
			"ProTestSpool()", err,  err != PRO_TK_NO_ERROR );

    return 0;
}

/*============================================================================*\
 Function:	ProUtilSetSpoolMenu
 Purpose:       Enable/Disable spool menu buttons
\*============================================================================*/
void ProUtilSetSpoolMenu(
    ProAssembly *p_assy)
{
    int n_spools = 0;
    ProCblSpool *p_spools;
    ProError err;


    err = ProCblAssemblySpoolsGet(*p_assy, &p_spools, &n_spools);
    TEST_CALL_REPORT( "ProCblAssemblySpoolsGet()", "ProUtilSetSpoolMenu()", 
	err,  err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
    ProUtilMenubuttonActivate("TkSpool", "Write", n_spools != 0);
    ProUtilMenubuttonActivate("TkSpool", "Edit", n_spools != 0);
    ProUtilMenubuttonActivate("TkSpool", "List", n_spools != 0);
    if (err == PRO_TK_NO_ERROR)
	ProArrayFree((ProArray*)&p_spools);

}


/*============================================================================*\
 Function:	ProTestSpoolCreate
 Purpose:       Create spool
\*============================================================================*/
ProError ProTestSpoolCreate(
    ProAssembly *p_assy,
    Procbl_cable_type cable_type,
    ProCblSpool	*p_spool)
{
    ProError err;
    Procbl_sheath_type sheath_type = PROCBL_BUNDLE_NONE;
    ProName  w_name;

    static ProUtilMenuButtons bundle_type[] = {
        {"TkSheath Type", 0, TEST_CALL_PRO_MENU_DELETE},
        {"None", PROCBL_BUNDLE_NONE, 0},
        {"Shrink", PROCBL_BUNDLE_SHRINK, 0},
        {"Tube", PROCBL_BUNDLE_TUBE, 0},
        {"Tape", PROCBL_BUNDLE_TAPE, 0},
        {"", 0, 0}
    };

    if ( cable_type == PROCBL_TYPE_BUNDLE)
    {
        err = ProUtilMenuIntValueSelect(bundle_type, (int *)&sheath_type);
        if (err != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
    }

    ProMessageDisplay(MSGFIL, "TEST Enter Spool name [QUIT]:");
    err =  ProMessageStringRead(PRO_NAME_SIZE, w_name);
    if (err != PRO_TK_NO_ERROR)
	return (PRO_TK_GENERAL_ERROR);

    err = ProCblSpoolCreate(*p_assy, w_name, cable_type, sheath_type,
	p_spool);
    TEST_CALL_REPORT( "ProCblSpoolCreate()", 
		    "ProTestSpoolCreate()", err,  err != PRO_TK_NO_ERROR );
    if (err != PRO_TK_NO_ERROR)
	return (PRO_TK_GENERAL_ERROR);

    ProMessageDisplay(MSGFIL, "TEST Spool has been created successfully.");
    err = ProTestSpoolParametersEdit(p_spool);

    return (PRO_TK_NO_ERROR);
}
    


/*============================================================================*\
 Function:	ProTestSpoolAction
 Purpose:       Upper level spool menu
\*============================================================================*/
int ProTestSpoolAction(
    ProAssembly *p_assy,
    int		action)
{
    ProError err;
    ProName  w_name, w_param_name, *wp_names = NULL;
    ProCharName name;
    ProCharLine	param_value;
    char file_name[PRO_PATH_SIZE];
    Procbl_cable_type cable_type;
    Procbl_sheath_type sheath_type;
    ProCblSpool	spool, *p_spools;
    int i, n_spools, n_logical, *p_selected, n_sel, n_param;
    wchar_t **w_menus;
    FILE *file;
    Pro_parameter_info param, *p_param;

    static ProUtilMenuButtons spool_type[] = {
	{"TkCreate Spool", 0, TEST_CALL_PRO_MENU_DELETE},
	{"Wire", PROCBL_TYPE_WIRE, 0 },
	{"Cable", PROCBL_TYPE_CABLE, 0 },
	{"Sheath", PROCBL_TYPE_BUNDLE,0 },
	{"From Logical", -1,0 },
	{"",0,0}
    };

    switch (action)
    {
    case TEST_SPOOL_READ:
	/* Open spool file */
    	err = ProUtilFileOpen("*.spl", file_name);
	if (err != PRO_TK_NO_ERROR)
	    break;
	/* Read parameters */
	err = ProUtilParametersFileRead(file_name, &p_param, &n_param);
	if (err != PRO_TK_NO_ERROR || n_param <=0)
	    break;
	err = ProUtilSpoolParametersToSpoolType(&p_param, &n_param, w_name,
	    &cable_type, &sheath_type);
	if (err != PRO_TK_NO_ERROR)
	    break;
	/* Create spool */
	err = ProCblSpoolCreate(*p_assy, w_name, cable_type, sheath_type,
	    &spool);
	TEST_CALL_REPORT( "ProCblSpoolCreate()", 
			"ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
	if (err == PRO_TK_NO_ERROR)
	{
	    ProMessageDisplay(MSGFIL, 
		"TEST Spool has been created successfully.");
	}
	break;
    case TEST_SPOOL_CREATE:
	err = ProCblSpoolFromLogicalGet(*p_assy, &wp_names, &n_logical);
        TEST_CALL_REPORT( "ProCblSpoolFromLogicalGet()", "ProTestSpoolAction()",	     err,  err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
	if (err == PRO_TK_NO_ERROR)
	{
	    spool_type[4].special_flag = 0;
	}
	else
	{
	    spool_type[4].special_flag = TEST_CALL_PRO_MENUBUTTON_DELETE;
	}

	err = ProUtilMenuIntValueSelect(spool_type, (int *)&cable_type);
	if (err != PRO_TK_NO_ERROR)
	{
	    if (wp_names)
		err = ProArrayFree((ProArray*)&wp_names);
	    break;
	}
	if ((int)cable_type == -1)
	{
	    /* From Logical */
	    err = ProUtilMenuStringsAlloc(&w_menus);
    	    for (i=0; i<n_logical; i++)
	    {	
		err = ProUtilMenuStringsWstrAdd(&w_menus, wp_names[i]);
	    }
	    err = ProUtilMenuStringManySelect("TkRef Spool", w_menus,
		&p_selected, &n_sel);
	    if (err == PRO_TK_NO_ERROR)
	    {
    		for (i=0; i<n_sel; i++)
		{	
		    err = ProCblSpoolFromLogicalCreate(*p_assy,
			wp_names+p_selected[i], 1, &p_spools);
	    	    TEST_CALL_REPORT( "ProCblSpoolFromLogicalCreate()", 
			"ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
		    if (err == PRO_TK_NO_ERROR)
		    {
			err = ProArrayFree((ProArray*)&p_spools);
			ProMessageDisplay(MSGFIL, 
			    "TEST Spool has been created successfully.");
		    }
		}
		ProArrayFree((ProArray*)&p_selected);
	    }
	}
	else    
	    ProTestSpoolCreate(p_assy, cable_type, &spool);
	if (wp_names)
	    err = ProArrayFree((ProArray*)&wp_names);

        break;
    case TEST_SPOOL_EDIT:
	err = ProTestSpoolSelect(p_assy, 0, -1, &spool);
	if (err != PRO_TK_NO_ERROR)
	    break;
        err = ProTestSpoolParametersEdit(&spool);
	break;
    case TEST_SPOOL_WRITE:
	err = ProTestSpoolSelect(p_assy, 0, -1, &spool);
	if (err != PRO_TK_NO_ERROR)
	    break;

	err = ProCblSpoolParametersGet(&spool, &p_param, &n_param);
	TEST_CALL_REPORT( "ProCblSpoolParametersGet()", 
			"ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
	if (err != PRO_TK_NO_ERROR)
	    return (err);
    
	err = ProCblSpoolNameGet(&spool, w_name);
	TEST_CALL_REPORT( "ProCblSpoolNameGet()", 
			"ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
	
	ProWstringToString(file_name, w_name);
	ProUtilStringLower(file_name, file_name);
	strcat(file_name, ".spl");

	file = fopen(file_name, "w");
	fprintf(file, "! Enter or modify parameters for the spool.\n");
	ProUtilParametersFileWrite(file, p_param, n_param);
	fclose(file);    
	ProMessageDisplay(MSGFIL, "TEST Output file %0s has been written.",
	    file_name);
	break;
    case TEST_SPOOL_LIST:
	err = ProCblAssemblySpoolsGet(*p_assy, &p_spools, &n_spools);
        TEST_CALL_REPORT( "ProCblSpoolSpoolGet()", "ProTestSpoolAction()", 
	    err,  err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
        if (err != PRO_TK_NO_ERROR)
            break;
	file = fopen(TEST_SPOOL_LIST_FILE, "w");
	ProStringToWstring(w_param_name, "TYPE");
	for (i=0; i<n_spools; i++)
	{    
	    err = ProCblSpoolNameGet(p_spools+i, w_name);
	    TEST_CALL_REPORT( "ProCblSpoolNameGet()", 
		    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
	    ProWstringToString(name, w_name);

	    err = ProCblSpoolParameterGet(p_spools+i, w_param_name,
		&param); 
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
		"ProTestSpoolAction()", 
		err,  err != PRO_TK_NO_ERROR && err != PRO_TK_E_NOT_FOUND );
	    ProWstringToString(param_value, param.value.strval);
	    fprintf(file, "%-32s %s\n", name, param_value);
	}
	err = ProArrayFree((ProArray*)&p_spools);
	fclose(file);	
	ProStringToWstring(w_name, TEST_SPOOL_LIST_FILE);
	err = ProInfoWindowDisplay(w_name, NULL, NULL);
	break;
    }
    ProUtilSetSpoolMenu(p_assy);
    return (0);
}   


/*============================================================================*\
 Function:	ProTestSpoolParametersEdit
 Purpose:       
\*============================================================================*/
ProError ProTestSpoolParametersEdit(
    ProCblSpool*p_spool)
{
    ProName w_name;
    ProError err;
    ProCblParameterInfo *p_param, *p_param2;
    int n_param, n_param2, i, j;
    FILE *file;
    ProCharLine file_name;
    ProLine w_file_name;
    
    err = ProCblSpoolParametersGet(p_spool, &p_param, &n_param);
    TEST_CALL_REPORT( "ProCblSpoolParametersGet()", 
		    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
    if (err != PRO_TK_NO_ERROR)
        return (err);
        
    err = ProCblSpoolNameGet(p_spool, w_name);
    TEST_CALL_REPORT( "ProCblSpoolNameGet()", 
		    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
    ProWstringToString(file_name, w_name);
    strcat(file_name, ".spl");
    ProStringToWstring(w_file_name, file_name);   
    
    file = fopen(file_name, "w");
    fprintf(file, "! Enter or modify parameters for the spool.\n");
    ProUtilParametersFileWrite(file, p_param, n_param);
    fclose(file);    
    err = ProFileEdit(w_file_name);
    TEST_CALL_REPORT("ProFileEdit()", "ProTestSpoolAction()", 
	err,  err != PRO_TK_NO_ERROR && err != PRO_TK_NO_CHANGE );
    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;
	/* Also delete each second parameter -  for testing purposes only */
	if ((j<n_param2) && (i & 1))
	    continue;
    
	/* Do not touch NAME and TYPE parameters */
	if (!ProUtilStrwscmp("NAME", p_param[i].name) || 
	    !ProUtilStrwscmp("TYPE", p_param[i].name) ||
	    !ProUtilStrwscmp("SHEATH_TYPE", p_param[i].name))
	    continue;

	/* Parameter was not found anymore - will be deleted */
	err = ProCblSpoolParameterDelete(p_spool, p_param[i].name);
	TEST_CALL_REPORT("ProCblSpoolParameterDelete()",
            	    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
    }
    /* Remove read-only parameters from file */
    ProUtilSpoolParametersToSpoolType(&p_param2, &n_param2, NULL, NULL, NULL);


    /* setup new parameter name */
    err = ProCblSpoolParametersSet (p_spool, p_param2, n_param2);
    TEST_CALL_REPORT("ProCblSpoolParametersSet()",
            	    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );

    ProUtilParametersFree(&p_param2, n_param);	
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:  ProUtilCblSpoolTypeGet
 Purpose:   Converts text parameter type for spool to Procbl_cable_type
\*============================================================================*/
ProError ProUtilCblSpoolTypeGet(
    ProCblParameterInfo *p_param,
    Procbl_cable_type *p_cable_type)
{
    if (p_param->value_type != PRO_WIDE_STRING_TYPE)
	return (PRO_TK_BAD_INPUTS);

    if (!ProUtilStrwscmp("WIRE", p_param->value.strval))
	p_cable_type[0] = PROCBL_TYPE_WIRE;
    else  if (!ProUtilStrwscmp("PREFAB", p_param->value.strval))
	p_cable_type[0] = PROCBL_TYPE_CABLE;
    else if (!ProUtilStrwscmp("SHEATH", p_param->value.strval))
	p_cable_type[0] = PROCBL_TYPE_BUNDLE;
    else
	return (PRO_TK_BAD_INPUTS);
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:  ProUtilSpoolParametersToSpoolType
 Purpose:   Convert read-only spool parameters to values adn remove it from list
\*============================================================================*/
ProError ProUtilSpoolParametersToSpoolType(
    ProCblParameterInfo **pp_param,	/* In/Out : the array  of  param */
    int *pn_param,			/* In/Out : the number of  param */
    ProName name,
    Procbl_cable_type *p_cable_type,
    Procbl_sheath_type *p_sheath_type)
{
    int i, nname = -1, ntype = -1, nsheath = -1;
    int n_param = *pn_param;
    ProCblParameterInfo *p_param = *pp_param;
    Procbl_cable_type cable_type;
    Procbl_sheath_type sheath_type =  PROCBL_BUNDLE_NONE;

    for (i=0; i<n_param; i++)
    {
	if (!ProUtilStrwscmp("NAME", p_param[i].name))
	{
	    if (name != NULL)
		ProUtilWstrcpy(name, p_param[i].value.strval);
	    nname = i;
	}
	else if (!ProUtilStrwscmp("TYPE", p_param[i].name))
	{   
	    ProUtilCblSpoolTypeGet(p_param+i, &cable_type);
	    ntype = i;
	}
	else if (!ProUtilStrwscmp("SHEATH_TYPE", p_param[i].name))
	{
	    if (!ProUtilStrwscmp("TAPE", p_param[i].value.strval))
		sheath_type = PROCBL_BUNDLE_TAPE;
	    else if (!ProUtilStrwscmp("TUBE", p_param[i].value.strval))
		sheath_type = PROCBL_BUNDLE_TUBE;
	    else
		sheath_type = PROCBL_BUNDLE_SHRINK;
	    nsheath = i;
	}
    }
    if (nname == -1 || ntype == -1)
	return (PRO_TK_GENERAL_ERROR);
    ProArrayObjectRemove((ProArray*)pp_param, nname, 1);
    ProArrayObjectRemove((ProArray*)pp_param, ntype-1, 1);
    if (p_cable_type != NULL)
	*p_cable_type = cable_type;
    if (p_sheath_type != NULL)
	*p_sheath_type = sheath_type;
    (*pn_param) -=2;
    if (nsheath != -1)
    {
	ProArrayObjectRemove((ProArray*)pp_param, nsheath-2, 1);
	(*pn_param)--;
    }
    return (PRO_TK_NO_ERROR);
}

/*============================================================================*\
 Function:  ProTestSpoolSelect
 Purpose:   Select existing or new spool
\*============================================================================*/
ProError ProTestSpoolSelect(
    ProAssembly *p_assy,
    int allow_new,
    Procbl_cable_type cable_type, 
    ProCblSpool *p_spool)
{
    ProCblSpool	*p_spools;
    Procbl_cable_type spool_type = (Procbl_cable_type)-1;
    ProError err;
    int i, n_spools, spool_num;
    wchar_t **w_menus;
    ProName w_name, w_param;
    ProCblParameterInfo param;

    err = ProCblAssemblySpoolsGet(*p_assy, &p_spools, &n_spools);
    TEST_CALL_REPORT( "ProCblAssemblySpoolsGet()", 
		    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );                       
    ProUtilMenuStringsAlloc(&w_menus);
    if (allow_new)
	ProUtilMenuStringsStrAdd(&w_menus, "Create");
    ProStringToWstring(w_param, "TYPE");
    for (i=0; i<n_spools; i++)
    {
	if (cable_type != -1)
	{
	    spool_type = (Procbl_cable_type)-1;
	    err = ProCblSpoolParameterGet(p_spools + i, w_param, &param);
	    TEST_CALL_REPORT( "ProCblSpoolParameterGet()", 
		"ProTestSpoolAction()", 
		err,  err != PRO_TK_NO_ERROR  && err != PRO_TK_E_NOT_FOUND);
	    if (err == PRO_TK_NO_ERROR)
		ProUtilCblSpoolTypeGet(&param, &spool_type);

	    if (spool_type != cable_type)
		continue;
	}

	err = ProCblSpoolNameGet(p_spools+i, w_name);
	TEST_CALL_REPORT( "ProCblSpoolNameGet()", 
		    "ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );

	ProUtilMenuStringsWstrAdd(&w_menus, w_name);
    }
    err = ProUtilMenuStringsIntValueSelect("TkSpool Names", w_menus, 
	&spool_num);
    if (err == PRO_TK_NO_ERROR)
    {
	if ((spool_num == 0) && allow_new)
	{
	    /* Create new spool */
	    err = ProTestSpoolCreate(p_assy, cable_type, p_spool);
	}
	else
	{
	    err = ProCblSpoolInit(*p_assy, w_menus[spool_num], p_spool);
	    TEST_CALL_REPORT( "ProCblSpoolInit()", 
			"ProTestSpoolAction()", err,  err != PRO_TK_NO_ERROR );
	}
    }

    ProUtilMenuStringsFree(&w_menus);
    ProArrayFree((ProArray*)&p_spools);
    return (err);
}
