/* Copyright (C) 1994 - 2001 by Telelogic AB.
Copyright (C) 1991, 1992, 1993, 1994 by Telelogic Malmoe AB.
Copyright (C) 1990, 1991, 1999 by Telesoft Europe AB.
This Program is owned by Telelogic and is protected by national
copyright laws and international copyright treaties. Telelogic
grants you the right to use this Program on one computer or in
one local computer network at any one time.
Under this License you may only modify the source code for the purpose
of adapting it to your environment. You must reproduce and include
any copyright and trademark notices on all copies of the source code.
You may not use, copy, merge, modify or transfer the Program except as
provided in this License.
Telelogic does not warrant that the Program will meet your
requirements or that the operation of the Program will be
uninterrupted and error free. You are solely responsible that the
selection of the Program and the modification of the source code
will achieve your intended result and that the results are actually
obtained. */

#include "cucf.h"

#define CUCF_ERROR(errorcode, errormessage) errormessage, 
const tEMSErrorMessage ErrorMessageArray[] =
{

#include "ems/errors.h"

"LAST_ERROR_MESSAGE"
};
#undef CUCF_ERROR

#if !defined(CODER_REMOVE_PATH) && (defined(CODER_EO_USER) || defined(CODER_EO_DEBUG))
/*************************************************
 *
 *  NAME: EPGetPath
 *
 */
char*
#ifdef CODER_EO_USER
EPGetPath(tCoder* Coder)
#else
EPGetPath(tCoder* Coder, unsigned long* OLength)
#endif
{
  char* CurrPath, *Path;
  tASN1TypeInfo* Type = (tASN1TypeInfo*)(Coder->EMS.ErrorPath.Fields[0]);
  unsigned long CurrField = 0, Length;
  unsigned char EPLength[CODER_PATH_DEEP];
  
  /* Count bytes */
#ifdef CODER_TI_NAMES
  Length = EPLength[0] = strlen(Type->TypeName);
#else
  while (Type->TypeClass == type_ASN1_DEFINED || 
         Type->TypeClass == type_ASN1_TAGGED  ||
         Type->TypeClass == type_ASN1_OPEN_ID)
    Type = ((tASN1Defined*)Type)->BaseType;

  Length = EPLength[0] = CUCFGetASN1TypeClassLength(Type);
#endif

  while(CurrField < Coder->EMS.ErrorPath.NumOfFields - 1)
    {
      switch(Type->TypeClass)
        {
        case type_ASN1_SEQUENCE:
        case type_ASN1_SET:
        case type_ASN1_CHOICE:
        case type_ASN1_OPEN:
          CurrField++;
          Type = ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->TypeInfo;
#ifdef CODER_TI_NAMES
          EPLength[CurrField] = strlen(((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Name) + 1;
#else
          EPLength[CurrField] = CUCFGetNumOfDigits(((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Index + 1) + 1;
#endif
          Length += EPLength[CurrField];
          break;
        case type_ASN1_SEQUENCE_OF:
        case type_ASN1_SET_OF:
          CurrField++;
          EPLength[CurrField] = CUCFGetNumOfDigits(*((tVMSULong*)(Coder->EMS.ErrorPath.Fields[CurrField])) + 1) + 2;
          Length += EPLength[CurrField];
          Type = ((tASN1StructOf*)Type)->BaseType;
          break;
        case type_ASN1_TAGGED:
        case type_ASN1_DEFINED:
        case type_ASN1_OPEN_ID:
          Type = ((tASN1Defined*)Type)->BaseType;
        default: 
          break;
        }
    }

  Path = CUCF_ALLOC(Length + 1, 0);
  MEMORY_ERROR_HANDLER_EXP(Path == NULL, Coder, return NULL, ec_MEM_NotEnoughMemory, NO_ARGS);

  /* Fill path */
  CurrField = 0;
  CurrPath = Path;
  Type = (tASN1TypeInfo*)(Coder->EMS.ErrorPath.Fields[0]);

#ifdef CODER_TI_NAMES
  memcpy(CurrPath, Type->TypeName, EPLength[0]);
#else
  while (Type->TypeClass == type_ASN1_DEFINED ||
         Type->TypeClass == type_ASN1_TAGGED  ||
         Type->TypeClass == type_ASN1_OPEN_ID)
    Type = ((tASN1Defined*)Type)->BaseType;

  memcpy(CurrPath, GetASN1TypeClass(Type), EPLength[0]);
#endif

  while(CurrField < Coder->EMS.ErrorPath.NumOfFields - 1)
    {
      switch(Type->TypeClass)
        {
        case type_ASN1_SEQUENCE:
        case type_ASN1_SET:
        case type_ASN1_CHOICE:
        case type_ASN1_OPEN:
          CurrPath += EPLength[CurrField];
          CurrField++;
          Type = ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->TypeInfo;
#ifdef CODER_TI_NAMES
          *CurrPath = '.';
          memcpy(CurrPath + 1, ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Name, EPLength[CurrField] - 1);
#else
          sprintf(CurrPath, ".%ld", ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Index + 1);
#endif
          break;
        case type_ASN1_SEQUENCE_OF:
        case type_ASN1_SET_OF:
          CurrPath += EPLength[CurrField];
          CurrField++;
          sprintf(CurrPath, "[%ld]", *((tVMSULong*)(Coder->EMS.ErrorPath.Fields[CurrField])) + 1);
          Type = ((tASN1StructOf*)Type)->BaseType;
          break;
        case type_ASN1_TAGGED:
        case type_ASN1_DEFINED:
        case type_ASN1_OPEN_ID:
          Type = ((tASN1Defined*)Type)->BaseType;
        default: 
          break;
        }
    }

  Path[Length] = '\0';
#ifdef CODER_EO_USER
  Coder->EMS.ErrorPath.PathLength = Length + 1;
  Coder->EMS.ErrorPath.Path = Path;
#else
  *OLength = Length + 1;
#endif
  return Path;
}
#endif /* !CODER_REMOVE_PATH && (CODER_EO_USER || CODER_EO_DEBUG)*/

/*************************************************
 *
 *  NAME: EPErrorHandler
 *
 */
void
EPErrorHandler(tCoder* Coder, int ErrorCode, ...)
{
#if defined(CODER_EO_USER)

  va_list ap;
  va_start(ap, ErrorCode);
  USERErrorOutputFunc(stderr, ErrorCode, ap);
  va_end(ap);
  CUCF_FREE(Coder->EMS.ErrorPath.Path, Coder->EMS.ErrorPath.PathLength, 0);

#elif defined(CODER_EO_DEBUG)

  fprintf(stderr, "ERROR %d ", ErrorCode);
  if (ErrorCode == ec_VAL_IllegalRealBase)
    fprintf(stderr, ErrorMessageArray[ErrorCode]);
  else
    {
      unsigned long Length = 0;
      char* Path = EPGetPath(Coder, &Length);
      
      fprintf(stderr, ErrorMessageArray[ErrorCode], 
              GetASN1TypeClass(Coder->VMS.Type),
              GetASN1TypeName(Coder->VMS.Type),
              Path);

#ifndef CODER_REMOVE_PATH
      if (Length != 0)
        CUCF_FREE(Path, Length, 0);
#endif
      fputc('\n', stderr);
    }

#elif defined(CODER_EO_SDT)

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

#ifdef XECODER
#define allocatedBytes  256
  char messageType[allocatedBytes];
  char messageInfo[allocatedBytes];

  messageType[allocatedBytes - 1] = 0;
  messageInfo[allocatedBytes - 1] = 0;
  snprintf(messageType, allocatedBytes-1, "\nERROR %d ", ErrorCode);
  
  if (ErrorCode == ec_VAL_IllegalRealBase)
    snprintf(messageInfo, allocatedBytes - 1, ErrorMessageArray[ErrorCode]);
  else
    {
#ifdef CODER_REMOVE_PATH
      snprintf(messageInfo, allocatedBytes - 1, ErrorMessageArray[ErrorCode], 
               GetASN1TypeClass(Coder->VMS.Type),
               GetASN1TypeName(Coder->VMS.Type), "undef");
#else
      unsigned long CurrField = 0;
      unsigned char WBytes, Length = 255;
      char* CurrPath = messageInfo;
      tASN1TypeInfo* Type = (tASN1TypeInfo*)(Coder->EMS.ErrorPath.Fields[0]);

      WBytes = snprintf(CurrPath, Length, ErrorMessageArray[ErrorCode],
                        GetASN1TypeClass(Coder->VMS.Type),
                        GetASN1TypeName(Coder->VMS.Type), "");
      CurrPath += WBytes;
      Length -= WBytes;

#ifdef CODER_TI_NAMES
      WBytes = snprintf(CurrPath, Length, "%s", Type->TypeName);
#else
      while (Type->TypeClass == type_ASN1_DEFINED ||
             Type->TypeClass == type_ASN1_TAGGED  ||
             Type->TypeClass == type_ASN1_OPEN_ID)
        Type = ((tASN1Defined*)Type)->BaseType;
          
      WBytes = snprintf(CurrPath, Length, "%s", GetASN1TypeClass(Type));
#endif

      while(CurrField < Coder->EMS.ErrorPath.NumOfFields - 1)
        {
          switch(Type->TypeClass)
            {
            case type_ASN1_SEQUENCE:
            case type_ASN1_SET:
            case type_ASN1_CHOICE:
            case type_ASN1_OPEN:
              CurrPath += WBytes;
              Length -= WBytes;
              CurrField++;
              Type = ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->TypeInfo;
#ifdef CODER_TI_NAMES
              WBytes = snprintf(CurrPath, Length, ".%s", 
                                ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Name);
#else                      
              WBytes = snprintf(CurrPath, Length, ".%ld", 
                                ((tASN1Component*)(Coder->EMS.ErrorPath.Fields[CurrField]))->Index + 1);
#endif
              break;
            case type_ASN1_SEQUENCE_OF:
            case type_ASN1_SET_OF:
              CurrPath += WBytes;
              Length -= WBytes;
              CurrField++;
              WBytes = snprintf(CurrPath, Length, "[%ld]", *(tVMSULong*)(Coder->EMS.ErrorPath.Fields[CurrField]) + 1);
              Type = ((tASN1StructOf*)Type)->BaseType;
              break;
            case type_ASN1_TAGGED:
            case type_ASN1_DEFINED:
            case type_ASN1_OPEN_ID:
              Type = ((tASN1Defined*)Type)->BaseType;
            default: 
              break;
            }
        }
#endif /* CODER_REMOVE_PATH */
    }
  xCoderError(messageType, messageInfo);
#undef allocatedBytes
#endif /* XECODER */

#ifdef _MSC_VER
#undef snprintf
#endif

#endif

  Coder->EMS.ErrorCode = ErrorCode;

#ifndef CODER_REMOVE_PATH
  /* Values initialization */
  if (BufGetErrInitFunc(Coder))
    BufErrInit(Coder);
  switch (ErrorCode)
    {
    case ec_VAL_WrongConstrainedValue:
    case ec_VAL_WrongConstrainedLength:
      return;
      
      /*        case ec_DEC_NoMoreDataForRead:
                case ec_DEC_WrongConstructedLengthPrefix:
                case ec_DEC_UnknownAlternative:*/
    default:
      break;
    }
#endif

  if (Coder->EMS.IsAssigned) longjmp(Coder->EMS.ReturnPoint, ErrorCode);
}

/**************************************************
 *
 * NAME: CUCFErrorHandler
 *
 *
 */

void
CUCFErrorHandler(tCoder* Coder, int ErrorCode, ...)
{
  va_list ap;

  Coder->EMS.ErrorCode = ErrorCode;
  va_start(ap, ErrorCode);

#if defined(CODER_EO_USER)

  USERErrorOutputFunc(stderr, ErrorCode, ap);

#elif defined(CODER_EO_DEBUG)

  fprintf(stderr, "ERROR %d ", ErrorCode);
  vfprintf(stderr, ErrorMessageArray[ErrorCode], ap);
  fputc('\n', stderr);

#elif defined(CODER_EO_SDT)

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

#ifdef XECODER
#define allocatedBytes  256
  {
    char messageType[allocatedBytes];
    char messageInfo[allocatedBytes];

    messageType[allocatedBytes - 1] = 0;
    messageInfo[allocatedBytes - 1] = 0;
    snprintf(messageType, allocatedBytes-1, "\nERROR %d ", ErrorCode);
    vsnprintf(messageInfo, allocatedBytes-1, ErrorMessageArray[ErrorCode], ap);
    xCoderError(messageType, messageInfo);
  }
#undef allocatedBytes
#endif

#ifdef _MSC_VER
#undef snprintf
#undef vsnprintf
#endif

#endif
  va_end(ap);

  if (Coder->EMS.IsAssigned) longjmp(Coder->EMS.ReturnPoint, ErrorCode);
}

/**************************************************
 *
 * NAME: CUCFGetErrorMessage
 *
 *
 */
char*
CUCFGetErrorMessage(tEMSErrorCode Code)
{
  return (char*)ErrorMessageArray[Code];
}

/**************************************************
 *
 * NAME: CUCFErrorOutput
 *
 *
 */
void
CUCFErrorOutput(FILE* File, tEMSErrorCode ErrorCode, ...)
{
  va_list ap;

  va_start(ap, ErrorCode);
#if defined(CODER_EO_USER)

  USERErrorOutputFunc(stderr, ErrorCode, ap);

#elif defined(CODER_EO_DEBUG)

  fprintf(stderr, "ERROR %d ", ErrorCode);
  vfprintf(stderr, ErrorMessageArray[ErrorCode], ap);
  fputc('\n', stderr);
  
#elif defined(CODER_EO_SDT)

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

#ifdef XECODER
#define allocatedBytes  256
  {
    char messageType[allocatedBytes];
    char messageInfo[allocatedBytes];
    
    messageType[allocatedBytes - 1] = 0;
    messageInfo[allocatedBytes - 1] = 0;
    snprintf(messageType, allocatedBytes-1, "\nERROR %d ", ErrorCode);
    vsnprintf(messageInfo, allocatedBytes-1, ErrorMessageArray[ErrorCode], ap);
    xCoderError(messageType, messageInfo);
  }
#undef allocatedBytes
#endif

#ifdef _MSC_VER
#undef snprintf
#undef vsnprintf
#endif

#endif
  va_end(ap);
}
