/* lib.c */

#include "main.h"
#include "lib.h"

extern char appname[];

/*
 * itoa
 * ----
 */
char *itoa(int i)
{
  static char s[16];
  sprintf(s,"%d",i);
  return s;
}

/*
 * set_filetype
 * ------------
 */
void set_filetype(char *filename, int filetype)
{
  _kernel_swi_regs regs;

  regs.r[0] = WRITE_CATINFO;
  regs.r[1] = (int)filename;
  regs.r[2] = filetype;
  _kernel_swi(OS_File, &regs, &regs);
}

/*
 * open_window
 * -----------
 */
void open_window(int win)
{
  int blk[9];
  _kernel_swi_regs regs;

  blk[0] = ro.win_data[win].win_handle;
  regs.r[1] = (int) blk;
  _kernel_swi(Wimp_GetWindowState, &regs, &regs);
  blk[7] = -1; // bring to front
  _kernel_swi(Wimp_OpenWindow, &regs, &regs);
}


/*
 * open_menu
 * ---------
 */
void open_menu(int x, int y, int menu_tag, int menu_struct)
{
  _kernel_swi_regs regs;

  // to recreate the menu if adjust is pressed
  static int prev_x, prev_y;
  if(x)
    prev_x = x;
  else if(prev_x)
    x = prev_x;
  else return;
  if(y)
    prev_y = y;
  else if(prev_y)
    y = prev_y;
  else return;

  regs.r[1] = menu_struct;
  regs.r[2] = x;
  regs.r[3] = y;
  _kernel_swi(Wimp_CreateMenu, &regs, &regs);

  ro.cur_menu = menu_tag;
}

/*
 * drag_start
 * ----------
 * Called when saving a file by dragging the icon.
 */
void drag_start(int winhdl, int iconhdl)
{
  _kernel_swi_regs  regs;
  int blk[9], box[10];
  char * spr;
  if(iconhdl == ICON_SAVE_WAV)
    spr = "file_fb1";
  else if(iconhdl == ICON_SAVE_MP3)
    spr = "file_1ad";
  else
    spr = "file_fff";

  box[0] = winhdl;
  box[1] = iconhdl;
  regs.r[1] = (int)box;
  _kernel_swi(Wimp_GetIconState, &regs, &regs);

  blk[0] = winhdl;
  regs.r[1] = (int)blk;
  _kernel_swi(Wimp_GetWindowState, &regs, &regs);

  box[2] += blk[1] - blk[5];
  box[3] += blk[4] - blk[6];
  box[4] += blk[1] - blk[5];
  box[5] += blk[4] - blk[6];

  regs.r[0] = 0;
  regs.r[1] = 1;
  regs.r[2] = (int)spr;
  regs.r[3] = (int)&box[2];
  _kernel_swi(DragASprite_Start, &regs, &regs);

  ro.drag = iconhdl;
}

/*
 * drag_return
 * -----------
 * called when a dragged file icon is dropped.
 */
void drag_return(char *name)
{
  _kernel_swi_regs  regs;
  int blk[64];

  if(ro.drag)
  {
    regs.r[1] = (int)blk;
    _kernel_swi(Wimp_GetPointerInfo, &regs, &regs);
    blk[5] = blk[3]; // window handle
    blk[6] = blk[4]; // icon handle
    blk[7] = blk[0]; // mouse x
    blk[8] = blk[1]; // mouse y
    blk[0] = sizeof(blk);
    blk[1] = 0;
    blk[2] = 0;
    blk[3] = 0;
    blk[4] = MESSAGE_DATASAVE;
    blk[9] = 0x1000; // size
    blk[10] = TEXT;
    strcpy((char *)&blk[11], name);

    regs.r[0] = 17;
    regs.r[1] = (int)blk;
    regs.r[2] = blk[5]; // window handle
    _kernel_swi(Wimp_SendMessage, &regs, &regs);

    _kernel_swi(DragASprite_Stop, &regs, &regs);
  }
}

/*
 * slider_value
 * ------------
 * Display new value for slider and update text value.
 * percent is now "per 1000"
 */
void slider_value(int win, int icon, int percent)
{
  _kernel_swi_regs regs;
  int b[10], line_len;

  b[0] = ro.win_data[win].win_handle;
  b[1] = icon;
  regs.r[1] = (int)b;
  _kernel_swi(Wimp_GetIconState, &regs, &regs);
  line_len = b[4] - b[2];
  b[1] = icon + 1;
  _kernel_swi(Wimp_GetIconState, &regs, &regs);

  regs.r[0] = b[0];
  regs.r[1] = b[1];
  regs.r[2] = b[2];
  regs.r[3] = b[3];
  regs.r[4] = b[2] + (line_len * percent) / 1000;
  regs.r[5] = b[5];
  _kernel_swi(Wimp_ResizeIcon, &regs, &regs);
  regs.r[0] = b[0];
  regs.r[1] = b[2];
  regs.r[2] = b[3];
  regs.r[3] = b[2] + line_len;
  regs.r[4] = b[5];
  _kernel_swi(Wimp_ForceRedraw, &regs, &regs);

  if(win == WIN_MAIN)
  {
    char s[8];
    sprintf(s,"%d%%", percent/10);
    icon_text_change(s, b[0], ICON_BAR_STR);
  }
}

/*
 * report_error_number
 * -------------------
 */
int report_error_number(int err, int flags)
{
  static char msg[80];

  flags |= FLG_OK | FLG_NO_ERROR | FLG_QUIET;

  if(msg_lookup("error", -err, msg))
    return report_error(msg, flags);
  else
    return report_error("Unknown error", flags);
}

/*
 * report_error
 * ---------------
 * Returns 1 if OK selected, 2 if Cancel selected
 */
int report_error(const char *errmess, int flags)
{
  _kernel_oserror blk;
  _kernel_swi_regs regs;

  int fatal = (flags == -1);
  if(fatal)
    flags = 2;

  blk.errnum = 1;
  strcpy(blk.errmess, errmess);
  regs.r[0] = (int)&blk;
  regs.r[1] = flags;
  regs.r[2] = (int)appname;
  _kernel_swi(Wimp_ReportError, &regs, &regs);

  if(fatal)
    exit(1);

  return regs.r[1];
}

/*
 * read_vdu_vars
 * -------------
 * Reads screen parameters
 */
void read_vdu_vars(void)
{
  _kernel_swi_regs regs;
  int b[5];

  b[0] = 4; // xeig
  b[1] = 5; // yeig
  b[2] = 11; // width
  b[3] = 12; // height
  b[4] = -1;
  regs.r[0] = regs.r[1] = (int)b;
  _kernel_swi(OS_ReadVduVariables, &regs, &regs);
  ro.vdu.width = (b[2] + 1) << b[0]; // screen width in os units
  ro.vdu.height = (b[3] + 1) << b[1]; // screen height in os units
}

/*
 * loadtemplate
 * ---------------
 */
int loadtemplate(const char *template_name, win_data_t *win_data, int entry)
{
  _kernel_swi_regs regs;
  int next_entry, name[4];

  strcpy((char *)name, template_name); // make sure it's 3 aligned words
  regs.r[1] = 0;  // find size
  regs.r[5] = (int)name;
  regs.r[6] = entry;
  _kernel_swi(Wimp_LoadTemplate, &regs, &regs);
  win_data->buffer = malloc(regs.r[1]);
  win_data->workspace = malloc(regs.r[2]);

  // load template
  regs.r[1] = (int)win_data->buffer;
  regs.r[3] = (int)win_data->workspace + regs.r[2];
  regs.r[2] = (int)win_data->workspace;
  regs.r[4] = -1;
  regs.r[6] = entry;
  _kernel_swi(Wimp_LoadTemplate, &regs, &regs);
  next_entry = regs.r[6];

  // centralise window
  int *b = (int*)win_data->buffer;
  int ww = b[2] - b[0]; // window width
  int wh = b[3] - b[1]; // window height
  b[0] = (ro.vdu.width / 2) - (ww / 2);
  b[1] = (ro.vdu.height / 2) - (wh / 2);
  b[2] = b[0] + ww;
  b[3] = b[1] + wh;

  // Create window
  regs.r[1] = (int)win_data->buffer;
  _kernel_swi(Wimp_CreateWindow, &regs, &regs);
  win_data->win_handle = regs.r[0];

  return next_entry;
}

/*
 * icon_text_change
 * -------------------
 */
void icon_text_change(char *text, int win_h, int icon_h)
{
   _kernel_swi_regs regs;
   int blk[16];

   // update string
   blk[0] = win_h;
   blk[1] = icon_h;
   regs.r[1] = (int)blk;
   _kernel_swi(Wimp_GetIconState, &regs, &regs);
   strcpy((char *)blk[7], text);

   // inform wimp
   blk[2] = 0;
   blk[3] = 0;
   regs.r[1] = (int)blk;
   _kernel_swi(Wimp_SetIconState, &regs, &regs);
}

/*
 * icon_disabled_change
 * --------------------
 * No action if state is not 0 or 1
 */
void icon_disabled_change(int state, int window, int icon)
{
  _kernel_swi_regs regs;
  int blk[4];

  if(state & ~1)
    return;

  blk[0] = window;
  blk[1] = icon;
  blk[2] = state << 22;
  blk[3] = 1 << 22;
  regs.r[1] = (int) blk;
  _kernel_swi(Wimp_SetIconState, &regs, &regs);
}


static int msg_desc[5];
static char * msg_buf;

/*
 * msg_open
 * --------
 */
int msg_open(const char * name)
{
  _kernel_swi_regs regs;

  if(msg_desc[4])
    return 1; // already open

  regs.r[1] = (int)name;
  if(_kernel_swi(MessageTrans_FileInfo, &regs, &regs))
    return 0; // error opening file

  if(regs.r[0] & 1)
    return 0; // already in memory

  if((msg_buf = malloc(regs.r[2])) == NULL)
    return 0; // out of memory

  regs.r[0] = (int)&msg_desc;
  regs.r[1] = (int)name;
  regs.r[2] = (int)msg_buf;
  _kernel_swi(MessageTrans_OpenFile, &regs, &regs);
  msg_desc[4] = 1;

  ro.flags |= (1<<MESSAGES_OPEN);

  return 1;
}

/*
 * msg_close
 * ---------
 */
void msg_close(void)
{
  _kernel_swi_regs regs;

  regs.r[0] = (int)&msg_desc;
  _kernel_swi(MessageTrans_CloseFile, &regs, &regs);
  msg_desc[4] = 0;

  if(msg_buf)
  {
    free(msg_buf);
    msg_buf = NULL;
  }
}

/*
 * msg_lookup
 * ----------
 * Converts a message token to text. Requires the base token string and
 * a numeric qualifier.
 * If qualifier is negative, uses token directly with no appended numeric.
 */
int msg_lookup(char * token, int num, char * dest)
{
  _kernel_swi_regs regs;
  char tok[32];

  if(!msg_desc[4])
    return 0; // Messages file not opened

  regs.r[0] = (int)&msg_desc;
  if(num < 0)
    regs.r[1] = (int)token;
  else
  {
    sprintf(tok, "%s%d", token, num);
    regs.r[1] = (int)&tok;
  }
  regs.r[2] = (int)dest;
  regs.r[3] = 256;
  regs.r[4] = 0;
  regs.r[5] = 0;
  regs.r[6] = 0;
  regs.r[7] = 0;
  if(_kernel_swi(MessageTrans_Lookup, &regs, &regs))
    return 0;

  return 1;
}

/*
 * msg_load_menu
 * -------------
 * Updates menu text from the messages file
 * Returns the next free location in the string store (str)
 */
char *msg_load_menu(char *token, char *str, menu_t *menu)
{
  int i;

  if(!msg_lookup(token, -1, str))
    return str;

  // title
  menu->text = str;
  i = 0;
  while((*str != ',') && *str) { i++; str++; }
  menu->len = i;
  if(!*str)
    return str + 1;
  *str = 0;

  // items
  menu_item_t *item = menu->item;
  while(1)
  {
    str++; // skip ','
    item->text = str;
    i = 0;
    while((*str != ',') && *str) { i++; str++; }
    item->len = i;
    if(!*str)
      return str + 1;
    *str = 0;
    if(item->item_flags == 0x80)
      return str + 1;
    item++;
  }

  return 0; // should never happen
}

/*
 * create/update menus
 * ---------------------------------------
 */
static const menu_item_t def_item = {0,-1,IC_DEF,NULL,NULL,0};

/*
 * update_menu
 * -----------
 * unticks everything, then ticks the 'cur' item.
 */
void update_menu(menu_item_t *item, int num, int cur)
{
  int i;

  for(i=0; i<num; i++)
    item[i].item_flags &= ~IT_TICKED;
  item[cur].item_flags |= IT_TICKED;
}

/*
 * create_numeric_menu
 * -------------------
 * creates the menu items of a numerical list
 */
char *create_numeric_menu(menu_item_t *item, int num, const int *value, char *str)
{
  int i, n;

  for(i=0; i<num; i++)
  {
    n = sprintf(str, "%d", value[i]);
    item[i] = def_item;
    item[i].text = str;
    item[i].len = n;
    str += n + 1;
  }
  item[0].item_flags = 256;
  item[num-1].item_flags = 128;
  return str;
}




