/*
  lib.c  riscos wimp functions

  created  17/2/24
*/

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

#define DRAG_SAVE 1
static int drag;


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


/*
 * icon_disabled_change
 * --------------------
 */
void icon_disabled_change(int state, int window, int icon)
{
  _kernel_swi_regs regs;
  int blk[4];

  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);
}


/*
 * icon_state_change
 * -------------------
 */
void icon_state_change(int state, int window, int icon)
{
  _kernel_swi_regs regs;
  int blk[4];

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


/*
 * icon_text_change
 * ----------------
 */
void icon_text_change(char *text, int window, int icon)
{
   _kernel_swi_regs regs;
   int blk[64];

   /* update string */
   blk[0] = window;
   blk[1] = icon;
   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);
}


/*
 * 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_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;
}


/*
 * open_window
 * -----------
 */
void open_window(int window)
{
  _kernel_swi_regs regs;
  int blk[64];

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


/*
 * drag_start
 * ----------
 * Called when saving a file by dragging the icon.
 */
void drag_start(int window, int icon)
{
  _kernel_swi_regs  regs;
  int blk[9], box[10];
  char * spr = "file_fff";

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

  blk[0] = window;
  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);

  drag = DRAG_SAVE;
}

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

  regs.r[1] = (int)blk;
  _kernel_swi(Wimp_GetPointerInfo, &regs, &regs);

  if (drag == DRAG_SAVE)
  {
    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] = 56;
    blk[1] = 0;
    blk[2] = 0;
    blk[3] = 0;
    blk[4] = MESSAGE_DATASAVE;
    blk[9] = 256; /* size */
    blk[10] = TEXT;
    strcpy((char *)&blk[11], ""); // we will add the leafname later

    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);
    drag = 0;
  }
}


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

  if(msg_lookup("error", err, msg))
    report_error(msg, fatal);
  else
    report_error("Unknown error", fatal);
}


/*
 * report_error
 * ------------
 */
int report_error(char *errmess, int flags)
{
  _kernel_oserror blk;
  _kernel_swi_regs regs;

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

  /* Returns 1 if OK selected, 2 if Cancel selected */
  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
}


/*
 * loadsprites
 * -----------
 * returns sprite area address or null for an error.
 */
int *loadsprites(const char *sprites)
{
  _kernel_swi_regs regs;
    int * area = 0;

  regs.r[0] = READ_CATINFO;
  regs.r[1] = (int)sprites;
  _kernel_swi(OS_File, &regs, &regs);
  if(regs.r[0] != IS_FILE)
    return 0;

  area = malloc(regs.r[4]+4);
  area[0] = regs.r[4]+4;
  area[1] = 0;
  area[2] = 16;
  area[3] = 16;
  regs.r[0] = 10+256;
  regs.r[1] = (int)area;
  regs.r[2] = (int)sprites;
  _kernel_swi(OS_SpriteOp, &regs, &regs);

  return area;
}


/*
 * loadtemplate
 * ---------------
 * returns window handle or zero
 */
int loadtemplate(const char *template_name, int *sprites)
{
  _kernel_swi_regs regs;
  int name[4];
  int * buffer;
  char * workspace;

  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] = 0;
  _kernel_swi(Wimp_LoadTemplate, &regs, &regs);
  buffer = malloc(regs.r[1]);
  workspace = malloc(regs.r[2]);

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

  if(!regs.r[6])
    return 0;

  if(sprites)
    buffer[16] = (int)sprites;

  // if needed, centralise window
  if(ro.flags & (1<<CENTRALISE))
  {
    int ww = buffer[2] - buffer[0]; // window width
    int wh = buffer[3] - buffer[1]; // window height
    buffer[0] = (ro.vdu.width / 2) - (ww / 2);
    buffer[1] = (ro.vdu.height / 2) - (wh / 2);
    buffer[2] = buffer[0] + ww;
    buffer[3] = buffer[1] + wh;
  }

  /* Create window */
  regs.r[1] = (int)buffer;
  _kernel_swi(Wimp_CreateWindow, &regs, &regs);

  return regs.r[0];
}


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

/*
 * msg_open
 * --------
 */
int msg_open(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;

  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,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[num-1].item_flags = 0x80;
  return str;
}

