/*
 * converter.c,v 1.1 1994/01/28 17:06:24 franktor Exp
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#ifdef __sun__
#include "sunos.h"
#endif
#include "config.h"
#include <sr-general.h>
#include <sr-converter.h>
#ifndef __CEXTRACT__
#include "proto.h"
#endif

/*
 * Global variables:
 */

Class *first_class;                     /* Start of linekd list of classes */


void
RegisterConverter (char *class_name, ConverterType type, char *conv_name,
                   void (*func)(void *))
{
  Converter *conv;
  Class *class;

  if (!class_name) {
    fprintf(stderr, "Illegal class.\n");
    return;
  }
  if (!conv_name) {
    fprintf(stderr, "Illegal name.\n");
    return;
  }

  class = FindClass(class_name);
  if (class == (Class *) NULL)
  {
    class = (Class *) malloc(sizeof(Class));
    class->converters = NULL;
    class->free_func = (void *) NULL;
    class->name = (char *) malloc(sizeof(char) * strlen(class_name) + 1);
    strcpy(class->name, class_name);
    if (first_class == (Class *) NULL)
    {
      first_class = class;
      class->next = NULL;
    }
    else
    {
      class->next = first_class;
      first_class = class;
    }
  }

  conv = FindConverter(class_name, conv_name);
  if (conv == (Converter *) NULL)
  {
    LOG(facHigh, llevDebug, "Registrating new converter: %s,%s",
        class_name, conv_name);
    conv = (Converter *) malloc(sizeof(Converter));
    conv->class = class;
    conv->name = (char *) malloc(sizeof(char) * strlen(conv_name) + 1);
    strcpy(conv->name, conv_name);
    conv->read_func = NULL;
    conv->write_func = NULL;
    if (class->converters == NULL)
    {
      class->converters = conv;
      conv->next = (Converter *) NULL;
    }
    else
    {
      conv->next = class->converters;
      class->converters = conv;
    }
  }

  switch (type)
  {
  case convert_in:
    if (conv->read_func)
      fprintf(stderr, "Warning: Previously registered converter overruled.\n");
    conv->read_func = (void *) func;
    break;
  case convert_out:
    if (conv->write_func)
      fprintf(stderr, "Warning: Previously registered converter overruled.\n");
    conv->write_func = (void *) func;
    break;
  }
}

void
RegisterClassFree(char *class_name, void (*func)(void *))
{
  Class *class;

  class = FindClass(class_name);
  if (class == (Class *) NULL)
  {
    fprintf(stderr, "Failed to find class %s\n", class_name);
    return;
  }

  class->free_func = (void *) func;
}

Converter *
FindConverter (char *class_name, char *conv_name)
{
  Class *class;
  Converter *tmp;

#if 0
  LOG(facHigh, llevTrace, "FindConverter(%s, %s)", class_name, conv_name);
#endif
  class = FindClass (class_name);
  if (class == (Class *) NULL) {
    LOG(facHigh, llevDebug, "No such class %s.", class_name);
    return (Converter *) NULL;
  }

  for (tmp = class->converters; tmp != (Converter *) NULL; tmp = tmp->next)
    if (!(strcmp(tmp->name, conv_name)))
      return tmp;

  LOG(facHigh, llevDebug, "No matching converter for %s.", conv_name);
  return (Converter *) NULL;
}

Class *
FindClass (char *class_name)
{
  Class *class;
  for (class = first_class; class != (Class *) NULL; class = class->next)
    if (!strcmp(class->name, class_name))
      return class;
  return (Class *) NULL;
}

CV_Status
Convert(char *name_class, char *name_in, char *name_out,
        void *data_in, void **data_out)
{
  Converter *converter_in, *converter_out;
  void *tmp_data; /* Pointer for internal data structure */
  Class *class;

  class = FindClass(name_class);
  if (class == (Class *) NULL) {
    LOG(facHigh, llevExceptions, "Converter: Didn't find class %s.", name_class);
    return CV_NoConverterFound;
  }

  converter_in = FindConverter(name_class, name_in);
  if (converter_in == (Converter *) NULL) {
    LOG(facHigh, llevExceptions, "Converter: Didn't find converter %s in class %s.", name_in, name_class);
    return CV_NoConverterFound;
  }

  converter_out = FindConverter(name_class, name_out);
  if (converter_out == (Converter *) NULL) {
    LOG(facHigh, llevExceptions, "Converter: Didn't find converter %s in class %s.", name_out, name_class);
    return CV_NoConverterFound;
  }

  if (!converter_in->read_func || !converter_out->write_func) {
    LOG(facHigh, llevExceptions, "Converter: Not initialised.");
    return CV_ConverterNotInitialised;
  }

  /* LOG(facHigh, llevTrace, "Converter: Reading."); */
  tmp_data = (void *) (*converter_in->read_func) (data_in);
  if (tmp_data == NULL)
    return CV_ConversionError;
  /* LOG(facHigh, llevTrace, "Converter: Done reading, starting writing."); */
  *data_out = (void *) (*converter_out->write_func) (tmp_data);

  if (class->free_func)
    (*class->free_func) (tmp_data);

  /* LOG(facHigh, llevTrace, "Converter: Returning OK."); */
  return CV_OK;
}
