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


/*--------------------------------------------------------------------*\
Pro/DEVELOP includes
\*--------------------------------------------------------------------*/


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include "ProToolkit.h"
#include "ProExtdata.h"
#include "ProUtil.h"

#include "UtilMessage.h"
#include "UtilFiles.h"
#include "TestError.h"
#include "TestGenedata.h"

/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/
#include <ctype.h>
#include <time.h>

/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
#define USER_MAX_STRING 120
#define USER_MAX_STREAM 120

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


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


/*--------------------------------------------------------------------*\
Application static data/function
\*--------------------------------------------------------------------*/
static int ProTestRdmSlotName(
        ProExtdataClass *p_class,
        int             maxsize,
        ProName         name,
        int             *format,
        char            **data);

static int ProTestRdmInt(
	);

static char ProTestRdmAlpha(
	);

static char ProTestRdmAlphaNum(
	);

static int ProTestRdmName(
        char *name,
        int maxlen);

static double ProTestRdmDouble(
	);

static int ProTestRdmFmt(
	);

static int ProTestRdmStr(
        int maxsize,
        char *str);

static unsigned char ProTestRdmByte(
	);

static int ProTestRdmStream(
        int maxsize,
        unsigned char **p_stream);

static int ProTestRdmKeyType(
	);



/*====================================================================*\
  Function : ProTestRdmSlotName
  Purpose  : Generate random slot name, data type and data
\*====================================================================*/
static int ProTestRdmSlotName(
	ProExtdataClass	*p_class,
        int		maxsize,
	ProName 	name,
	int		*format,
	char		**data)
{ 
      char	s_name[PRO_NAME_SIZE];
      int	*p_int;
      double	*p_double;
      wchar_t	*wstr;
      char      str[USER_MAX_STRING], dummy[PRO_NAME_SIZE];
          
      ProWstringToString(dummy, p_class->class_name);
      ProTestRdmName(s_name, (PRO_NAME_SIZE-strlen(dummy)-1));   

      ProStringToWstring(name, s_name);

      *format = ProTestRdmFmt();
      switch(*format)
      {
        case PRO_INTEGER_TYPE :
        p_int = (int*)calloc(1,sizeof(int));
        *p_int = ProTestRdmInt();
        (*data)=(char*)p_int;
        return(sizeof(int));
        break;
    case PRO_DOUBLE_TYPE :
        p_double = (double*)calloc(1,sizeof(double));
        *p_double = ProTestRdmDouble();
        (*data)=(char*)p_double;
        return(sizeof(double));
        break;
    case PRO_WIDE_STRING_TYPE :
        ProTestRdmStr(PRO_LINE_SIZE,str);
        wstr = (wchar_t*)calloc(strlen(str)+1,sizeof(wchar_t));
        ProStringToWstring(wstr,str);
        (*data)=(char*)wstr;
        return((strlen(str)+1) * sizeof(wchar_t));
        break;
    case PRO_STREAM_TYPE :
        return(ProTestRdmStream(maxsize,(unsigned char **)data));
        break;
    default :
        return(1);
    }
}

/*====================================================================*\
  Function : ProTestRdmInt
  Purpose  : Generate random int
\*====================================================================*/
static int ProTestRdmInt()
{
    unsigned int i=0;
    int b;
 
    for(b=0;b<sizeof(int);b++)
        i = (i<<8) + ProTestRdmByte();
    return((int)i);
}

/*====================================================================*\
  Function : ProTestRdmAlpha
  Purpose  : Generate  alphabetical string
\*====================================================================*/
static char ProTestRdmAlpha()
{
    static char *a=(char*)"abcdefghijklmnopqrstuvwxyz_";
 
    return(a[rand() % 27]);
}

/*====================================================================*\
  Function : ProTestRdmAlpha
  Purpose  : Generate  alphabetical-numerical mixed string
\*====================================================================*/
static char ProTestRdmAlphaNum()
{
    static char *a=(char*)"abcdefghijklmnopqrstuvwxyz_0123456789";
 
    return(a[rand() % 37]);
}

/*====================================================================*\
  Function : ProTestRdmName
  Purpose  : Generate random name string
\*====================================================================*/ 
static int ProTestRdmName(
	char *name,
	int maxlen)
{
    int len,i;
 
    do{
        len = rand() % maxlen;
    } while(len == 0);
    name[0] = ProTestRdmAlpha();
    for(i=1;i<len;i++)
        name[i]=ProTestRdmAlphaNum();
    name[len]='\0';
    return(1);
}

/*====================================================================*\
  Function : ProTestRdmDouble
  Purpose  : Generate random double
\*====================================================================*/ 
static double ProTestRdmDouble()
{
    double i,d;
 
    i = (double)rand();
    d = (double)rand();
    while(d > 1.0)
        d = d/10.0;
    if(rand() % 2)
        return(i+d);
    else
        return(-i-d);
}

/*====================================================================*\
  Function : ProTestRdmFmt
  Purpose  : Generate random data format
\*====================================================================*/ 
static int ProTestRdmFmt()
{
    static int a[] = {  PRO_INTEGER_TYPE,
                        PRO_DOUBLE_TYPE,
                        PRO_WIDE_STRING_TYPE,
                        PRO_STREAM_TYPE};
    return(a[rand() % 4]);
}

/*====================================================================*\
  Function : ProTestRdmStr
  Purpose  : Generate random string
\*====================================================================*/ 
static int ProTestRdmStr(
	int maxsize,
	char *str)
{
    int len,i;
 
    do{
        len = rand() % USER_MAX_STRING;
    } while (len==0 || len > maxsize);
    for(i=0;i<len;i++)
        do {
            str[i]=(char)(rand() % 128);
        } while(!isprint(str[i]));
 
    str[len] = '\0';
    return(strlen(str));
}

/*====================================================================*\
  Function : ProTestRdmByte
  Purpose  : Generate random type
\*====================================================================*/
static unsigned char ProTestRdmByte()
{
    return((unsigned char)(rand() % 256));
}

/*====================================================================*\
  Function : ProTestRdmStream
  Purpose  : Generate random stream
\*====================================================================*/ 
static int ProTestRdmStream(
	int maxsize,
  	unsigned char **p_stream)
{
    int len,i;
 
    do{
        len = rand() % USER_MAX_STREAM;
    } while (len==0 || len > maxsize);
    *p_stream = (unsigned char*)calloc(len,1);
    for(i=0;i<len;i++)
        (*p_stream)[i]=(unsigned char)(rand() % 256);
    return(len);
}

/*====================================================================*\
  Function : ProTestRdmKeyType
  Purpose  : Generate random key type
\*====================================================================*/ 
static int ProTestRdmKeyType()
{
    static int a[]={KEY_BY_NAME, KEY_BY_ID};
    return(a[rand() % 2]);
}

/*====================================================================*\
  Function : ProTestSvRdmData
  Purpose  : Save the random data to random slot
\*====================================================================*/
ProError ProTestSvRdmData(
	ProExtdataClass	*p_class,
	int		maxsize)
{
    ProExtdataSlot	p_slot;
    ProName		slot_name;
    ProExtdataErr	err;
    int size,totalsize=0;
    int type, key_type, n_slots;
    char *data;
    long t1,t2;
 
    t1 = time(NULL);
    n_slots = 0;
 
/*-------------------------------------------------------------*\
    While the volume of data is still less than asked..
\*-------------------------------------------------------------*/
    while(totalsize<maxsize)
    {
/*-------------------------------------------------------------*\
        Generate a random slot name, not bigger than the
        remaining size needed.
\*-------------------------------------------------------------*/
        size = ProTestRdmSlotName(p_class, maxsize-totalsize, slot_name,
                                        &type, &data);
 
/*-------------------------------------------------------------*\
        Get at random KEY_BY_NAME or KEY_BY_ID, and
        create the slot accordingly
\*-------------------------------------------------------------*/
        key_type = ProTestRdmKeyType();

        if(key_type == KEY_BY_NAME)
        {
 	    err = ProExtdataSlotCreate(p_class, slot_name, &p_slot);
        }
        else
        {
            err = ProExtdataSlotCreate(p_class, NULL, &p_slot);
        }
  
        TEST_CALL_REPORT("ProExtdataSlotCreate()", "ProTestSvRdmData( )",
                                (ProError)err, (ProError)err != PRO_TK_NO_ERROR &&
                                err != PROEXTDATA_TK_CLASS_OR_SLOT_EXISTS);

        if(err == PROEXTDATA_TK_CLASS_OR_SLOT_EXISTS)
        {
            ProUtilMsgPrint("gendata","TEST Slot %0ws already exists",slot_name);
            continue;
        }

        n_slots++;

        if(err != PROEXTDATA_TK_NO_ERROR)
        {
            ProUtilMsgPrint("gendata","TEST ProExtdataSlotCreate() status : %0s",
                    ProTestProAppdataErr(err));
            continue;
        }
 
/*-------------------------------------------------------------*\
        Write the random data to the slot
\*-------------------------------------------------------------*/
        err = ProExtdataSlotWrite(&p_slot, key_type, type, size, data); 

        TEST_CALL_REPORT("ProExtdataSlotWrite()", "ProTestSvRdmData( )",
                                (ProError)err, (ProError)err != PRO_TK_NO_ERROR);

        if(err != PROEXTDATA_TK_NO_ERROR)
        {
            ProUtilMsgPrint("gendata","TEST ProExtdataSlotWrite() : status %0s",
                    ProTestProAppdataErr(err));
            return(PRO_TK_GENERAL_ERROR);
        }

        free(data);
        totalsize+=size;
 
        if(n_slots%100 == 0)
        {
            t2 = time(NULL) - t1;
            ProUtilMsgPrint("gendata","TEST Saved %0d slots, %1d bytes in %2d seconds"
,
                                &n_slots, &totalsize, &t2);
        }
    }
    t2 = time(NULL) - t1;
    ProUtilMsgPrint("gendata","TEST Time to save %0d bytes was %1d seconds",
                                &totalsize, &t2);
 
    return(PRO_TK_NO_ERROR);
}