/*
 ******************************************************************************
 *  Copyright 1995 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * DeltaLink Decoder Task
 *
 * File: decoder.c
 *
 * This file contains the DeltaLink general purpose Decoder Task. This
 * task communicates with DeltaLink Protocol Drivers via the Mailbox Communication
 * Interface (MCI) V3 and en -decodes the data. 
 *
 */
#include  <stdlib.h>
#include  <string.h>
#include  <stdio.h>
#include  <stdarg.h>
#include  <math.h>

#include  <../../version.h>             /*  FactoryLink definitions */

#include  <flib.h>                      /*  FactoryLink definitions */

#ifdef OS2hhh
#include  <dos.h>
#endif

#include  <g_utils.h>
#include  <fl_utils.h>
#include  <modules.h>

#include  <mci3.h>                       /*  Mailbox Communication Interface definitions */
#include  <format3.h>                    /*  Mailbox Communication Interface definitions */

#include  <decoder.h>                    /*  DeltaLink  Protocol Decoder definitions */


DEC_TIME   dec_time[ 10];


/*-----------------------------------------------------------------------------
 * FUNCTION:  int dec_get_key( char *d, char *s, int *index)
 *
 * PURPOSE :  Get keyword out of string
 *
 -----------------------------------------------------------------------------*/
int dec_get_key( char *d, char *s, int *index)
{

  int    i = 0,
         k = 0;


  /* clear output string */
  d[ k] = '\0';

  /* skip leading spaces */
  while( ((s[ i] == ' ') || (s[ i] == ',')) && (s[ i] != '\0'))
    i++;
 
  /* copy keyword to destination */ 
  while( (s[ i] != ' ') && (s[ i] != ',') && (s[ i] != '\0'))
  {

    d[ k] = s[ i];
    k++;
    i++;
  }

  d[ k] = '\0';

  /* return string position */
  *index = i;

  return strlen( d);
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  int dec_load_time_conv( char *c)
 *
 * PURPOSE :  Load specified timer conversion.
 *
 -----------------------------------------------------------------------------*/
int dec_load_time_conv( char *c)
{

  char     *conv,
           key[ 80];
  int      i,
           k,
           byte = 0,
           index = 0;


  /* get the translated string */
  if (!strcmp( (conv = fl_xlate( c)), c))
    return ERROR; 

  /* convert string to upper case */
  for(i = 0; i < (int)strlen( conv); i++)
    conv[ i] = toupper( conv[ i]);

  i = atoi( &c[ 3]);

  dec_time[ i].hr   = -1;
  dec_time[ i].mi   = -1;
  dec_time[ i].sc   = -1;
  dec_time[ i].yp   = -1;
  dec_time[ i].yr   = -1;
  dec_time[ i].year = -1;
  dec_time[ i].mn   = -1;
  dec_time[ i].dy   = -1;
  dec_time[ i].dow  = -1;

  /* 
   * There is a string, now fill in the structure 
   */

  /* get the coding of the data */
  if (!dec_get_key( key, conv, &index))
    return ERROR;

  /* check for BCD option */
  if (strcmp( key, "BCD"))
  {

    /* check BIN option */
    if (strcmp( key, "BIN"))
      return ERROR;
  }
  else
    dec_time[i].bcd = 1;


  /* get the time elements position */
  while (dec_get_key( key, &conv[ index], &k)) 
  {

    index += k;

    /* empty byte */
    if (!strcmp( key, "X"))
    {

      byte++;
      continue;
    }

    /* byte position hour */
    if (!strcmp( key, "HR"))
    {

      dec_time[ i].hr = byte++;  
      continue;
    }

    /* byte position minute */
    if (!strcmp( key, "MI"))
    {

      dec_time[ i].mi = byte++;  
      continue;
    }

    /* byte position second */
    if (!strcmp( key, "SC"))
    {

      dec_time[ i].sc = byte++;  
      continue;
    }

    /* byte position year */
    if (!strcmp( key, "YP"))
    {

      dec_time[ i].yp = byte++;  
      continue;
    }

    /* byte position year */
    if (!strcmp( key, "YR"))
    {

      dec_time[ i].yr = byte++;  
      continue;
    }

    /* byte position complete year in a word */
    if (!strcmp( key, "YEAR"))
    {

      dec_time[ i].year = byte;
      byte += 2;
      continue;
    }

    /* byte position month */
    if (!strcmp( key, "MO") || !strcmp( key, "MO1"))
    {

      dec_time[ i].mn = byte++;  
      dec_time[ i].mn_offset = 1;
      continue;
    }

    /* byte position month */
    if (!strcmp( key, "MO0"))
    {

      dec_time[ i].mn = byte++;  
      continue;
    }

    /* byte position day */
    if (!strcmp( key, "DY") || !strcmp( key, "DY1"))
    {

      dec_time[ i].dy = byte++;  
      dec_time[ i].dy_offset = 1;
      continue;
    }

    /* byte position day */
    if (!strcmp( key, "DY0"))
    {

      dec_time[ i].dy = byte++;  
      continue;
    }

    /* byte position day of week */
    if (!strcmp( key, "DOW") || !strcmp( key, "DOW1"))
    {

      dec_time[ i].dow = byte++;  
      dec_time[ i].dow_offset = 1;
      continue;
    }

    /* byte position day of week */
    if (!strcmp( key, "DOW0"))
    {

      dec_time[ i].dow = byte++;  
      continue;
    }

    /* if we get here, we have an unknown key... */
    return ERROR;
  }

  /* set the length of the time strucuture */
  dec_time[ i].size = byte;

  return GOOD;
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  int dec_init_time_conv()
 *
 * PURPOSE :  Load timer conversions.
 *
 -----------------------------------------------------------------------------*/
int dec_init_time_conv()
{

  int   ret = GOOD;
  int   i;
  char  key[ 20];


  /* time conversions */
  for (i = 0; i < 10; i++)
  {

    /* construct the key word */
    sprintf( key, "TIM%1d", i); 

    if (dec_load_time_conv( key) != GOOD)
      ret = ERROR;
  }

  return ret;
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  u32 dec_time2long(char *s, int len, int index)
 *
 * PURPOSE :  Conversion from time message string to long.
 *
 -----------------------------------------------------------------------------*/
u32 dec_time2long(uchar *s, int len, int index)
{

  KDT      kdt;
  int      i,
           k;
  u16      u16_var;


  /*
   * typedef struct _KDT
   * {
   *   u16     hours;                   hours (0-23) 
   *   u16     minutes;                 minutes (0-59) 
   *   u16     seconds;                 seconds (0-59) 
   *   u16     hundredths;              hundredths of seconds (0-99) 
   *   u16     day;                     day of month (1-31) 
   *   u16     month;                   month (1-12) 
   *   u16     year;                    year (1980-2097) 
   *   u16     weekday;                 day of week (0=Sun,...,6=Sat) 
   *   u16     timezone;                time zone (relative to GMT) 
   * } KDT;
   */

  if (dec_time[ index].size > len)
    return 0L;

  memset( &kdt, 0, sizeof( KDT));

  /* correct for BCD */
  if (dec_time[ index].bcd)
  {

    /* convert every byte in string to binair */
    for( k = 0; k < len; k++)
    {

      /* convert the byte */
      for( i = 0, u16_var = 0; i < 2; i++)
        u16_var += (u16)((double)(( s[ k] >> (i * 4)) & 0x000F) * pow( (double )10, ( double)i));

      s[ k] = (uchar)u16_var;
    }
  }

  /* 
   * convert to kdt structure 
   */

  if (dec_time[ index].hr > -1)
    kdt.hours = s[ dec_time[ index].hr];

  if (dec_time[ index].mi > -1)
    kdt.minutes = s[ dec_time[ index].mi];

  if (dec_time[ index].sc > -1)
    kdt.seconds = s[ dec_time[ index].sc];

  if (dec_time[ index].dy > -1)
    kdt.day = s[ dec_time[ index].dy] + 1 - dec_time[ index].dy_offset;
  else
    kdt.day = 1;

  if (dec_time[ index].mn > -1)
    kdt.month = s[ dec_time[ index].mn] + 1 - dec_time[ index].mn_offset;
  else
    kdt.month = 1;

  if (dec_time[ index].yp > -1)
    kdt.year = 100 * s[ dec_time[ index].yp];
  else
  {

    /* estimate the prefix */
    if (dec_time[ index].yr > -1)
    {

      if ((s[ dec_time[ index].yr] - 80) < 0)
        kdt.year = 2000;
      else
        kdt.year = 1900;
    }
  }

  if (dec_time[ index].yr > -1)
    kdt.year += s[ dec_time[ index].yr];

   /* update the word year */

  if (dec_time[ index].year > -1)
    kdt.year = *( u16 *)&s[ dec_time[ index].year ];

 if (dec_time[ index].dow > -1)
    kdt.weekday = s[ dec_time[ index].dow] - dec_time[ index].dow_offset;

 return dl_kdt2time( &kdt);
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  void dec_long2time(char *s, u32 time, int index)
 *
 * PURPOSE :  Conversion from numeric time (long) to time string.
 *
 -----------------------------------------------------------------------------*/
void dec_long2time(uchar *s, u32 time, int index)
{

  KDT      kdt;
  int      i,
           k;
  u16      u16_var;


  /* convert value to kdt strucuture */
  dl_time2kdt( &kdt, time);

  /* fill in the string */
  if (dec_time[ index].hr > -1)
    s[ dec_time[ index].hr] = (uchar)kdt.hours;

  if (dec_time[ index].mi > -1)
    s[ dec_time[ index].mi] = (uchar)kdt.minutes;

  if (dec_time[ index].sc > -1)
    s[ dec_time[ index].sc] = (uchar)kdt.seconds;

  if (dec_time[ index].dy > -1)
    s[ dec_time[ index].dy] = (uchar)(kdt.day - 1 + dec_time[ index].dy_offset);

  if (dec_time[ index].mn > -1)
    s[ dec_time[ index].mn] = (uchar)(kdt.month - 1 + dec_time[ index].mn_offset);

  if (dec_time[ index].yp > -1)
    s[ dec_time[ index].yp] = (uchar)(kdt.year / 100);

  if (dec_time[ index].yr > -1)
    s[ dec_time[ index].yr] = (uchar)(kdt.year % 100);

  /* update the word year */

  if (dec_time[ index].year > -1)
    *( u16 *)&s[ dec_time[ index].year ] = kdt.year;

  if (dec_time[ index].dow > -1)
    s[ dec_time[ index].dow] = (uchar)(kdt.weekday + dec_time[ index].dow_offset);

  /* check for bcd */
  if (dec_time[ index].bcd)
  {

    /* go through all the bytes */
    for( k = 0; k< dec_time[ index].size; k++)
    {

      /* convert the byte */
      for( i = 0, u16_var = 0; i < 2; i++)
      {

        u16_var |= (((u16)s[ k] % (u16)10) << (i * 4));
        s[ k] = (uchar)((u16)s[ k] / (u16)10);
      }

      s[ k] = (uchar)u16_var;
    }
  }

  return;
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  int strpos( char *src, const char *token)
 *
 * PURPOSE :  Get index of token in search string.
 *
 -----------------------------------------------------------------------------*/
int strpos( char *src, const char *token)
{

  char    *token_pos;


  if ((token_pos = strstr( src, token)) != NULL)
    return (int)( token_pos - src);
  else
    return -1;                               
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  void tmfmt_load( TMFMT *t, char *fmt)
 *
 * PURPOSE :  Load time conversion for message tags.
 *
 -----------------------------------------------------------------------------*/
void tmfmt_load( DEC_TMFMT *t, char *fmt)
{


  /* return in case of null pointer */
  if (t == NULL)
    return;

  /* make the string caps independent, go to lower case */
  strlower( fmt);

  /*
   * Find the location where the string is used.
   * Save the relative position in the TMFMT buffer. If not found store -1
   */
  t->year = strpos( fmt, "year");
  t->yr   = strpos( fmt, "yr");
  t->mon  = strpos( fmt, "mon");

  /*
   * Since 'mo' is a part of 'mon' we need to distinguish
   */
  t->mo = strpos( fmt, "mo");

  if ((t->mon != -1) && (t->mon == t->mo))
    t->mo = strpos( &fmt[ t->mon+2], "mo");

  t->dy   = strpos( fmt, "dy");
  t->dow  = strpos( fmt, "dow");
  t->hr   = strpos( fmt, "hr");
  t->ah   = strpos( fmt, "ah");
  t->mi   = strpos( fmt, "mi");
  t->sc   = strpos( fmt, "sc");
  t->ap   = strpos( fmt, "ap");

  /*
   * Copy the format string into the structure for later use
   */
  strncpy( t->fmt, fmt, MAX_DATETIME);

  /*
   * Load alpha months 
   */
  strcpy( t->amon[  0], fl_xlate("MO0"));
  strcpy( t->amon[  1], fl_xlate("MO1"));
  strcpy( t->amon[  2], fl_xlate("MO2"));
  strcpy( t->amon[  3], fl_xlate("MO3"));
  strcpy( t->amon[  4], fl_xlate("MO4"));
  strcpy( t->amon[  5], fl_xlate("MO5"));
  strcpy( t->amon[  6], fl_xlate("MO6"));
  strcpy( t->amon[  7], fl_xlate("MO7"));
  strcpy( t->amon[  8], fl_xlate("MO8"));
  strcpy( t->amon[  9], fl_xlate("MO9"));
  strcpy( t->amon[ 10], fl_xlate("M10"));
  strcpy( t->amon[ 11], fl_xlate("M11"));

  /*
   * Load alpha days 
   */
  strcpy( t->adow[  0], fl_xlate("DOW0"));
  strcpy( t->adow[  1], fl_xlate("DOW1"));
  strcpy( t->adow[  2], fl_xlate("DOW2"));
  strcpy( t->adow[  3], fl_xlate("DOW3"));
  strcpy( t->adow[  4], fl_xlate("DOW4"));
  strcpy( t->adow[  5], fl_xlate("DOW5"));
  strcpy( t->adow[  6], fl_xlate("DOW6"));
  
  /*
   * Load alpha am/pm
   */
  strcpy( t->aap[  0], fl_xlate("DAM"));
  strcpy( t->aap[  1], fl_xlate("DPM"));

  return;
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  void tmfmt_load( TMFMT *t, char *fmt)
 *
 * PURPOSE :  Convert the time (long, 'SECTIME') to char string.
 *
 -----------------------------------------------------------------------------*/
char *fmt_time( char *d, DEC_TMFMT *t, LANA st)
{

  KDT kdt;        /* Kernel Date Time Structure */
  char  buf[5];   /* Temp Buffer */
  int   len;        /* Lenght of String */
  short ap = 0;


  /*
   * Transform the SECTIME value to the KDT structure.
   */
  dl_time2kdt( &kdt, st);
 
  /*
   * Copy the fmt string as the base to the destination string
   */
  strcpy( d, t->fmt);
  len = strlen( d);

  /*
   * Simply substitute the tokens with the numbers. the location
   * were the tokens are is set within the TMFMT struct.
   */
  if ((t->year != -1) && (t->year < (len - 3)))
  {

    sprintf( buf, "%04d",kdt.year);
    memcpy( &d[t->year], buf, 4);
  }

  if ((t->yr != -1) && (t->yr < len - 1))
  {

    /* Make sure the year is correct 00..99 */
    kdt.year %= 100;

    sprintf( buf, "%02d",kdt.year);
    memcpy( &d[t->yr], buf, 2);
  }

  if ((t->mon != -1) && (t->mon < len - 2))
    memcpy( &d[t->mon], t->amon[ kdt.month-1], 3);

  if ((t->mo != -1) && (t->mo < len - 1))
  {

    sprintf( buf, "%02d",kdt.month);
    memcpy( &d[t->mo], buf, 2);
  }

  if ((t->dy != -1) && (t->dy < len - 1))
  {

    sprintf( buf, "%02d", kdt.day);
    memcpy( &d[t->dy], buf, 2);
  }

  if ((t->hr != -1) && (t->hr < len - 1))
  {

    sprintf( buf, "%02d",kdt.hours);
    memcpy( &d[t->hr], buf, 2);
  }

  if ((t->ah != -1) && (t->ah < len - 1))
  {

    sprintf( buf, "%02d", kdt.hours % 12);
    memcpy( &d[t->ah], buf, 2);
  }

  if ((t->mi != -1) && (t->mi < len - 1))
  {

    sprintf( buf, "%02d",kdt.minutes);
    memcpy( &d[t->mi], buf, 2);
  }

  if ((t->sc != -1) && (t->sc < len - 1))
  {

    sprintf( buf, "%02d",kdt.seconds);
    memcpy( &d[t->sc], buf, 2);
  }

  if ((t->dow != -1) && (t->dow < len - 2))
    memcpy( &d[t->dow], t->adow[ kdt.weekday], 3);

  if ((t->ap != -1) && (t->ap < len - 1))
  {

    if (kdt.hours > 12)
      ap = 1;  

    memcpy( &d[t->ap], t->aap[ ap], 2);
  }

  return d;
}


/*-----------------------------------------------------------------------------
 * FUNCTION:  LANA get_fmt_time( char *d, DEC_TMFMT *t)
 *
 * PURPOSE :  Convert the time (message) to long, 'SECTIME'.
 *
 -----------------------------------------------------------------------------*/
LANA get_fmt_time( char *d, DEC_TMFMT *t)
{

  KDT kdt;        /* Kernel Date Time Structure */
  char  buf[5];   /* Temp Buffer */
  int   i;


  /*
   * Fill the kdt structure
   */

  memset( &kdt, 0, sizeof( KDT));

  buf[ 2] = '\0';

  if (t->hr != -1)
    kdt.hours = atoi( strncpy( buf, &d[ t->hr], 2));
  else
  {

    if (t->ah != -1)
      kdt.hours = atoi( strncpy( buf, &d[ t->ah], 2));
    
    if (t->ap != -1)
    {

      if (!memcmp( &d[ t->ap], fl_xlate("DPM"), 2))
       kdt.hours += 12;
    }
  }

  if (t->mi != -1)
  {

    buf[ 2] = '\0';
    kdt.minutes = atoi( strncpy( buf, &d[ t->mi], 2));
  }

  if (t->sc != -1)
  {

    buf[ 2] = '\0';
    kdt.seconds = atoi( strncpy( buf, &d[ t->sc], 2));
  }

  if (t->year != -1)
  {

    buf[ 4] = '\0';
    kdt.year = atoi( strncpy( buf, &d[ t->year], 4));
  }
  else
  {

    if (t->yr != -1)
    {

      buf[ 2] = '\0';
      kdt.year = atoi( strncpy( buf, &d[ t->yr], 2)) + 1900;
    }

    if (kdt.year < 1980)
      kdt.year += 100;
  }

  if (t->dy != -1)
  {

    buf[ 2] = '\0';
    kdt.day = atoi( strncpy( buf, &d[ t->dy], 2));
  }
  
  if (t->mo != -1)
  {

    buf[ 2] = '\0';
    kdt.month = atoi( strncpy( buf, &d[ t->mo], 2));
  }

  if (t->dow != -1)
  {

    buf[ 4] = '\0';

    for( i = 0; i < 7; i++)
    {

      /* search the day */
      if (!memcmp( &d[ t->dow], t->adow[ i], 3))
        break;
    }

    if (i < 7)
      kdt.weekday = i;
  }

  if ((t->mon != -1) && (t->mo == -1))
  {

    buf[ 4] = '\0';

    for( i = 0; i < 12; i++)
    {

      /* search the day */
      if (!memcmp( &d[ t->dow], t->amon[ i], 3))
        break;
    }

    if (i < 12)
      kdt.month = i;
  }

  /*
   * Transform the KDT strucuture to SECTIME value
   */
  return dl_kdt2time( &kdt);
}
 
