/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,	*/
/*      	1994 - 2005, All Rights Reserved		        */
/*									*/
/* MODULE NAME : mvl_dtyp.c   						*/
/* PRODUCT(S)  : MMSEASE-LITE						*/
/*									*/
/* MODULE DESCRIPTION : 						*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*	NONE								*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev			Comments			*/
/* --------  ---  ------   -------------------------------------------	*/
/* 01/19/05  JRB     08    Use mvlu_trim_branch_name from mvl_uca.c	*/
/* 12/19/02  JRB     07    Use ms_comp_name_find, ms_comp_name_pres.	*/
/* 11/19/02  RKR     06    Corrected size in cardinality function	*/
/* 02/27/02  JRB     05    Del unneeded prototypes & includes.		*/
/* 12/04/01  RKR     04    ported to QNX cleaned up errors and warnings */
/* 11/09/01  RKR     03    resorted the num_rt_blks			*/
/* 01/21/00  MDE     02    Now use MEM_SMEM for dynamic memory		*/
/* 10/05/99  RKR     01    Created					*/
/************************************************************************/

#include "glbtypes.h"
#include "sysincs.h"

#include "mmsdefs.h"
#include "mms_pvar.h"
#include "mms_vvar.h"
#include "mms_pvmd.h"
#include "mms_err.h"
#include "mms_pcon.h"
#include "mvl_log.h"
#include "mvl_defs.h"
#include "mvl_uca.h"	/* need mvlu_trim_branch_name	*/
#include "asn1defs.h"
#include "stime.h"

/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of 	*/
/* __FILE__ strings.							*/
/************************************************************************/

#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif

static ST_UCHAR  *create_bitstring (ST_INT num);
static ST_VOID   set_bit ( ST_UCHAR *bptr, ST_INT i);
static ST_BOOLEAN ismember( ST_UCHAR	*bptr,
		     ST_INT	n);
static ST_VOID reSortRT (RUNTIME_TYPE *rt, ST_INT numRt);
static ST_VOID  add_to_branch_name (ST_CHAR *branch_name, SD_CONST ST_CHAR *SD_CONST sub_branch_name);

static ST_INT cardinality (ST_UCHAR *bptr, ST_INT size);
static ST_VOID calc_offset_to_last (RUNTIME_TYPE *rt);

ST_VOID mvl_print_type( ST_CHAR *base_name, ST_INT typeIdIn);
#ifndef __ECOS
ST_BOOLEAN u_mvl_rt_element_supported (RUNTIME_TYPE *rt, 
				       ST_CHAR *element_name,
				       ST_RTREF *ui, ST_CHAR *handle);
#endif
ST_VOID adjRtBlks( RUNTIME_TYPE *derived_type_table, ST_INT derived_count);

/************************************************************************/
/*                           mvl_derive_new_type                        */
/************************************************************************/

ST_RET  mvl_derive_new_type (ST_CHAR *base_name, ST_INT typeIdIn, ST_INT *typeIdOut, ST_CHAR *handle)
  {
ST_RET  ret;
ST_RTREF rtrefs;
ST_UCHAR *membership;

  ret = mvl_derive_type_members (base_name, typeIdIn, &membership, &rtrefs, handle );
  mvl_print_derived_type (base_name, typeIdIn, membership, rtrefs);
  ret = mvl_add_derived_type (base_name, typeIdIn, membership, rtrefs, typeIdOut);
  return (ret);  
  }

/************************************************************************/
/*                     mvl_derive_type_members                          */
/************************************************************************/

ST_RET  mvl_derive_type_members (ST_CHAR *base_name, ST_INT typeIdIn, 
				 ST_UCHAR **membership, ST_RTREF *rtrefs, ST_CHAR *handle)
  {
ST_RET          ret = SD_FAILURE;
RUNTIME_TYPE    *rt;
ST_INT          num_rt;
ST_BOOLEAN      exists;
ST_CHAR         element_name[MAX_IDENT_LEN+1];  
ST_CHAR         branch_name[MAX_IDENT_LEN+1];  
ST_RTREF        *user_info;
ST_INT          i;
ST_RTREF        ui;    /* let the user pass back widget of unknown purpose */
ST_UCHAR        *bptr;

  ret = mvl_get_runtime (typeIdIn, &rt, &num_rt);
  if (ret != SD_SUCCESS)
    {
    MVL_LOG_NERR1 ("TypeId %d not found",typeIdIn);	     
    return (ret);
    }

  bptr = create_bitstring (num_rt);
  *membership = bptr;
  user_info = (ST_RTREF *) M_CALLOC (MSMEM_GEN, num_rt, sizeof(ST_RTREF *));
  *rtrefs = user_info;

  for (i=0; i<num_rt; i++)
    {
    exists = SD_FALSE;

    if ((rt[i].el_tag == RT_STR_START) && (ms_comp_name_pres(&rt[i])))
      {
      add_to_branch_name (branch_name, ms_comp_name_find(&rt[i]));
      strcpy (element_name, branch_name);
      }
    else
      {
      if (ms_comp_name_pres(&rt[i]))
	sprintf (element_name, "%s$%s", branch_name, ms_comp_name_find(&rt[i]));
      else
	{
	if (i==0)       /* This is the start of the entire RuntimeType  */
	  {
	  strcpy (branch_name, base_name);
	  strcpy (element_name, branch_name);
	  }
	else
	  element_name[0]=0;    /* nobody home */
	}
      }

    if (rt[i].el_tag == RT_STR_END)
      {
      strcpy( element_name, branch_name);
      mvlu_trim_branch_name (branch_name);
      }

    ui = rt[i].mvluTypeInfo.ref;
#ifndef __ECOS
    exists = u_mvl_rt_element_supported(&rt[i], element_name, &ui, handle);
#endif
    if (exists)
      {
      set_bit (bptr, i);
      user_info[i] = ui;
      }
    }

  return (ret);
  }


/************************************************************************/
/*                          mvl_add_derived_type                        */
/************************************************************************/

ST_RET  mvl_add_derived_type( ST_CHAR *base_name, ST_INT typeIdIn, 
			      ST_UCHAR *membership, ST_RTREF *rtrefs,
			      ST_INT *typeIdOut)
  {
ST_RET          ret;
ST_INT          derived_elements;
RUNTIME_TYPE    *derived_type_table;
ST_INT          derived_count;
RUNTIME_TYPE    *rt;
ST_INT          num_rt;
ST_INT          i;


  ret = mvl_get_runtime (typeIdIn, &rt, &num_rt);
  if (ret != SD_SUCCESS)
    {
    MVL_LOG_NERR1 ("TypeId %d not found",typeIdIn);	     
    return (ret);
    }

  /* count how many elements are in the new type                        */
  derived_elements = cardinality( membership, num_rt);

  /* allocate a new RT type table about that large                      */
  derived_type_table = (RUNTIME_TYPE *)M_CALLOC (MSMEM_GEN, derived_elements,
						   sizeof(RUNTIME_TYPE));

  /* copy the elements marked as members of the new type into the new   */
  /* RT type table                                                      */
  derived_count = 0;
  for(i=0; i<num_rt; i++)
    {
    if (ismember (membership, i))
      {
      memcpy (&derived_type_table[derived_count], &rt[i], sizeof(RUNTIME_TYPE));
      derived_type_table[derived_count].mvluTypeInfo.ref = rtrefs[i];
      derived_count++;
      }
    }

  M_FREE (MSMEM_GEN, membership);
  M_FREE (MSMEM_GEN, rtrefs);

  /* fix up the offsets.                                                */
  for (i=0; i<derived_count; i++)
    {
    calc_offset_to_last(&derived_type_table[i]);
    }

  /* fix up the number of RuntimeBlocks contained in arrays and structures */
  adjRtBlks(derived_type_table,derived_count);

  /* resort the UCA names so GNL will return sorted strings */
  reSortRT (derived_type_table, derived_count);

  /* we get to finally add a MVL type!                                  */
  ret = mvlu_add_rt_type (derived_type_table, derived_count, typeIdOut);
 
  /*mvl_print_type (base_name, *typeIdOut);*/
  return (ret);
  }

/************************************************************************/
/*                          mvl_print_type                      */
/************************************************************************/
#if 0
ST_VOID mvl_print_type( ST_CHAR *base_name, ST_INT typeIdIn)
  {
ST_RET          ret;
ST_INT          i;
RUNTIME_TYPE    *rt;
ST_INT          num_rt;
ST_CHAR         element_name[MAX_IDENT_LEN+1];  
ST_CHAR         branch_name[MAX_IDENT_LEN+1];  

  ret = mvl_get_runtime (typeIdIn, &rt, &num_rt);
  if (ret != SD_SUCCESS)
    {
    MVL_LOG_NERR1 ("TypeId %d not found",typeIdIn);	     
    }

  for (i=0; i<num_rt; i++)
    {
    if ((rt[i].el_tag == RT_STR_START) && (ms_comp_name_pres(&rt[i])))
      {
      add_to_branch_name (branch_name, ms_comp_name_find(&rt[i]));
      strcpy( element_name, branch_name);
      }
    else
      {
      if (ms_comp_name_pres(&rt[i]))
	sprintf( element_name, "%s$%s", branch_name, ms_comp_name_find(&rt[i]));
      else
	{
	if ( i==0 )     /* This is the start of the entire RuntimeType  */
	  {
	  strcpy( branch_name, base_name);
	  strcpy( element_name, branch_name);
	  }
	else
	  element_name[0]=0;    /* nobody home */
	}
      }

    if (rt[i].el_tag == RT_STR_END)
      {
      strcpy( element_name, branch_name);
      mvlu_trim_branch_name (branch_name);
      }

    _slogc (sLogCtrl,"RT %d '%s' - sortedNum %d",
            i,element_name,rt[i].mvluTypeInfo.sortedNum);
    }
  }
#endif
/************************************************************************/
/*                          mvl_print_derived_type                      */
/************************************************************************/

ST_VOID mvl_print_derived_type( ST_CHAR *base_name, ST_INT typeIdIn, 
				ST_UCHAR *membership, ST_UCHAR **labels)
  {
ST_RET          ret;
ST_INT          i;
RUNTIME_TYPE    *rt;
ST_INT          num_rt;
ST_CHAR         element_name[MAX_IDENT_LEN+1];  
ST_CHAR         branch_name[MAX_IDENT_LEN+1];  

  ret = mvl_get_runtime (typeIdIn, &rt, &num_rt);
  if (ret != SD_SUCCESS)
    {
    MVL_LOG_NERR1 ("TypeId %d not found",typeIdIn);	     
    }

  for (i=0; i<num_rt; i++)
    {
    if ((rt[i].el_tag == RT_STR_START) && (ms_comp_name_pres(&rt[i])))
      {
      add_to_branch_name (branch_name, ms_comp_name_find(&rt[i]));
      strcpy( element_name, branch_name);
      }
    else
      {
      if (ms_comp_name_pres(&rt[i]))
	sprintf( element_name, "%s$%s", branch_name, ms_comp_name_find(&rt[i]));
      else
	{
	if ( i==0 )     /* This is the start of the entire RuntimeType  */
	  {
	  strcpy( branch_name, base_name);
	  strcpy( element_name, branch_name);
	  }
	else
	  element_name[0]=0;    /* nobody home */
	}
      }

    if (rt[i].el_tag == RT_STR_END)
      {
      strcpy( element_name, branch_name);
      mvlu_trim_branch_name (branch_name);
      }

    /*if ( ismember( membership, i))
      {
      printf ( "\n RT %d  element name '%s'",i,element_name);
      _slogc (sLogCtrl,"RT %d '%s' - sortedNum %d",
		     i,element_name,rt[i].mvluTypeInfo.sortedNum);
      }*/
    }
  }

/************************************************************************/
/*                            reSortRT                                  */
/************************************************************************/

static ST_VOID reSortRT (RUNTIME_TYPE *rt, ST_INT numRt)
  {
ST_INT  highestSortNum;
ST_INT  i;
ST_INT  prevSortNum;
ST_INT  newSortNum;

  /* First find the highest 'used' sort number */

  highestSortNum = 0;
  for (i = 0; i < numRt; ++i)
    {
    if (rt[i].mvluTypeInfo.sortedNum > highestSortNum)
      highestSortNum = rt[i].mvluTypeInfo.sortedNum;
    }

  newSortNum = 1;

/* compress the sort numbers */

  for (prevSortNum = 1; prevSortNum <= highestSortNum; ++prevSortNum)
    {
    for (i = 0; i < numRt; ++i)
      {
      if (rt[i].mvluTypeInfo.sortedNum == prevSortNum)
        {
        rt[i].mvluTypeInfo.sortedNum = newSortNum;
        ++newSortNum;
        break;
        }
      }
    }    
  }
/************************************************************************/
/*		                adjRtBlks				*/
/************************************************************************/

ST_VOID adjRtBlks( RUNTIME_TYPE *derived_type_table, ST_INT derived_count)
  {
RUNTIME_TYPE *nested[ASN1_MAX_LEVEL];
ST_INT i;
ST_INT curNestLevel;
RUNTIME_TYPE *start_rt_blk;
RUNTIME_TYPE *rt_ptr;
ST_INT	num_rt;

  curNestLevel = 0;

  rt_ptr = derived_type_table;
  for (i=0; i<derived_count; i++,rt_ptr++)
    {
    if ((rt_ptr->el_tag == RT_STR_START) ||
          (rt_ptr->el_tag == RT_ARR_START))
      {
      nested[curNestLevel] = rt_ptr;  /* remember where we started */
      curNestLevel++;
      }
    else if ((rt_ptr->el_tag == RT_STR_END) ||
              (rt_ptr->el_tag == RT_ARR_END))
      {
      curNestLevel--;
      start_rt_blk = nested[curNestLevel];
      num_rt = (rt_ptr - start_rt_blk - 1); /* figure out how many in between */

      /*if (start_rt_blk->u.str.num_rt_blks != num_rt)
        {
	printf ("\n adjusting %s, was %d, is now %d",
                   ms_comp_name_find(start_rt_blk),
	           start_rt_blk->u.str.num_rt_blks,
		   num_rt);
	}*/

      start_rt_blk->u.str.num_rt_blks = num_rt;
      rt_ptr->u.str.num_rt_blks = num_rt;
      }
    }
  }

/************************************************************************/
/*                            add_to_branch_name                        */
/************************************************************************/

static ST_VOID  add_to_branch_name (ST_CHAR *branch_name, SD_CONST ST_CHAR *SD_CONST sub_branch_name)
  {
  sprintf( branch_name, "%s$%s", branch_name, sub_branch_name);
  }

/************************************************************************/
/*                          create_bitstring                            */
/************************************************************************/
static ST_UCHAR *create_bitstring (ST_INT n)
  {
ST_INT i,j;
ST_UCHAR *s;

  i = n / ( sizeof( ST_UCHAR ) * 8 );
  j = n % ( sizeof( ST_UCHAR ) * 8 );

  if (j) 
    i++;  /* allocate an extra byte if string len ! a multiple of 8 */
  
  s = (ST_UCHAR *)M_CALLOC (MSMEM_GEN, i, sizeof( ST_UCHAR));
  return(s);

  }

/************************************************************************/
/*                              set_bit                                 */
/************************************************************************/
static ST_VOID set_bit (ST_UCHAR *s, ST_INT n)
  {
ST_INT          i,j;
ST_UCHAR        k = 0x01;  /* mask */

  i = n / ( sizeof( ST_UCHAR ) * 8 );
  j = n % ( sizeof( ST_UCHAR ) * 8 );
  s[ i ] = s[ i ] | ( k << j );
  }

/************************************************************************/
/*                              ismember                                        */
/* This function returns 1 if element n belongs to Set s, 0 otherwise.  */
/************************************************************************/

static ST_BOOLEAN ismember( ST_UCHAR   *bptr,
		     ST_INT     n)
  {
ST_INT           i,j;
ST_UCHAR         k = 0x01;  /* mask */

  i = n / ( sizeof( ST_UCHAR ) * 8 );
  j = n % ( sizeof( ST_UCHAR ) * 8 );
  return( bptr[ i ] & ( k << j ));
  }

/************************************************************************/
/*                          cardinality                                 */
/************************************************************************/

static ST_INT cardinality (ST_UCHAR *bptr, ST_INT size)
  {
ST_INT          i, j, s, r, card;
ST_CHAR         temp;

  s = size / ( sizeof( ST_UCHAR ) * 8 );
  r = size % ( sizeof( ST_UCHAR ) * 8 );

  if (r) 
    s++; 
  card=0;
  for ( i = 0; i < s; i++ ) 
    {
    for ( j = 0; j < 8 * sizeof( ST_UCHAR ); j++ ) 
      {
      temp = 0x01;
      temp = temp << j;
      if ( temp & bptr[ i ] ) 
	card++;
      }
    }
  return( card );
  }

/************************************************************************/
/*                          calc_offset_to_last                         */
/************************************************************************/
/* This function would not be needed except that the UCA structure      */
/* handling needs to know the size of each subelement too ...           */

static ST_VOID calc_offset_to_last (RUNTIME_TYPE *rt) 
  {
ST_INT numUcaRt;

  if (rt->el_tag == RT_ARR_END ||  rt->el_tag == RT_STR_END)
    {
    return;
    }

  if (rt->el_tag == RT_STR_START)
    numUcaRt = rt->u.str.num_rt_blks+2;
  else if (rt->el_tag == RT_ARR_START)
    numUcaRt = rt->u.arr.num_rt_blks+2;
  else
    numUcaRt = 1;

/* Now we can find the size of this element and it's associates */
  rt->offset_to_last = ms_get_blocked_length (rt, numUcaRt);
  }


