#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "kernel.h"
#include "swis.h"

#include "ka_error.h"

#include "ka_log.h"
#include "msg.h"

static _kernel_oserror error_block;

/**
 * Returns the version of a module.
 *
 * @param  name      Module name.
 *
 * @return Module version*100 or -1 if module is not present in RMA.
 */
int rm_version(const char* name)
{
  int* addr;
  const char* help;
  int count;
  int found_vers = -1;


  // find module in RMA
  if (!_swix(OS_Module, _INR(0,1)|_OUT(3), 18, name, &addr))
  {
    // check version
    help = (char*) addr;
    help += addr[5];
    count = 0;
    while(count < 16)
    {
      count++;
      if (*help == 9)
      {
        count += 7;
        count &= ~7;
      }
      help++;
    }
    if (help[1] == '.')
      found_vers = (help[0] - '0') * 100
                 + (help[2] - '0') * 10
                 + (help[3] - '0');
  }
  return found_vers;
}

static void wimp_reporterror(const _kernel_oserror* blk)
{
  const char* app = "KinoAMP Player";
  _swix(Wimp_ReportError, _INR(0, 2)
    , blk
    , 8 // flags: bit3 = no Press Space from Command line
    , app);
}

/**
 * Displays an error message and exits if it's a fatal ome.
 *
 * @param  fatal   Positive if fatal error leading to program termination.
 *                 Negative if shouldn't look for format token in msg file.
 * @param  format  printf like format.
 * @param  ...     Additional parameters, format dependant.
 */
void report_error(int fatal, const char *format, ...)
{
  char msg[240];
  va_list arg;

  va_start(arg, format);

  error_block.errnum = 0; // error number

  if (fatal >= 0)
  {
    msg_lookup(format, -1, msg, sizeof(msg));
    vsnprintf(error_block.errmess, sizeof(error_block.errmess), msg, arg);
  }
  else
  {
    vsnprintf(error_block.errmess, sizeof(error_block.errmess), format, arg);
  }
  va_end(arg);

  ka_log(ka_log_error, "%s", error_block.errmess);

  if (fatal)
  {
    wimp_reporterror(&error_block);
    exit(1);
  }
}

/**
 * Writes a message into a string.
 *
 * @param  str     String to write message into.
 * @param  format  printf like format.
 * @param  ...     Additional parameters, format dependant.
 *
 * @returns A pointer to the string.
 */
char* report_vstring(char* str, int len, const char *format, va_list arg)
{
  char msg[240];

  msg_lookup(format, -1, msg, sizeof(msg));
  vsnprintf(str, len, msg, arg);

  return str;
}

/**
 * Writes a message into a string.
 *
 * @param  str     String to write message into.
 * @param  format  printf like format.
 * @param  ...     Additional parameters, format dependant.
 *
 * @returns A pointer to the string.
 */
char* report_string(char* str, int len, const char *format, ...)
{
  char msg[240];

  va_list arg;
  va_start(arg, format);

  msg_lookup(format, -1, msg, sizeof(msg));
  vsnprintf(str, len, msg, arg);

  va_end(arg);

  return str;
}

/**
 * Writes a message into an error block.
 *
 * @param  error   Errror block to write message into.
 * @param  format  printf like format.
 * @param  ...     Additional parameters, format dependant.
 *
 * @returns A pointer to the string.
 */
ka_error_t* ka_error_fill(ka_error_t* error, const char* format, ...)
{
  char msg[240];

  va_list arg;
  va_start(arg, format);

  msg_lookup(format, -1, msg, sizeof(msg));
  vsnprintf(error->errmess, sizeof(error->errmess), msg, arg);

  va_end(arg);

  return error;
}

/**
 * Displays an error message.
 */
void report_error_block(const ka_error_t* error)
{
  error_block = *error;
  ka_log(ka_log_error, "%s", error->errmess);
}

void report_lasterror(void)
{
  wimp_reporterror(&error_block);
}
