/* Copyright 1996 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*  > C.Arthur */
/*  Copyright (C) Acorn Computers Ltd., 1988 */

#include "arthur.h"
#include <stdarg.h>
/*
** Things in the Arthur C library.
**
** See also S.ArthurAsm for the OS bits
*/

int art_osbyte1(int, int);

art_error *art_osbyte(art_reg_set *regs)
{
        return art_swix(OS_Byte, regs);
}

int art_osbyte1(int num, int arg)
{
        art_reg_set a;

        a.r[0] = num;
        a.r[1] = arg & 0xff;
        a.r[2] = arg >> 8;

        arg = (int)art_osbyte(&a);

        return (a.r[1] & 0xff) | (a.r[2] << 8);
}

art_error *art_osword(int action, void *data)
{
        art_reg_set a;

        a.r[0] = action;
        a.r[1] = (int)data;

        return art_swix(OS_Word, &a);
}

art_error *art_osgbpb(art_osgbpb_block * data)
{
        return art_swix(OS_GBPB, (art_reg_set *)data);
}

art_error *art_osfile(art_osfile_block *data)
{
        return art_swix(OS_File, (art_reg_set *)data);
}

art_error *art_osargs(art_reg_set *regs)
{
        return art_swix(OS_Args, regs);
}

art_error *art_osfind(art_reg_set *regs)
{
        return art_swix(OS_Find, regs);
}

int art_adval(int x)
{
        return art_osbyte1(128, x);
}

void art_clg()
{ art_vdu(16);
}

void art_cls()
{ art_vdu(12);
}

void art_colour(int c)
{ art_vdu(17);
  art_vdu(c);
}

/* note: cursor ends up on circle */

void art_circle(int x,int y,int r)
{ art_move(x,y);
  art_plot(0x95,x+r,y);
}

void art_circlefill(int x,int y,int r)
{ art_move(x,y);
  art_plot(0x9D,x+r,y);
}

void art_cursor(int c)
{
art_vduq(23,1,c,0,0,0,0,0,0,0);
}

void art_draw(int x,int y)
{ art_vdu(25);art_vdu(5);
  art_vduw(x);art_vduw(y);
}

void art_drawby(int x,int y)
{ art_vdu(25);art_vdu(1);
  art_vduw(x);art_vduw(y);
}

void art_fill(int x,int y)
{
art_plot(0x85,x,y);
}

void art_gcol(int a,int b)
{ art_vdu(18);art_vdu(a);art_vdu(b);
}

void art_gwindow(int a,int b,int c,int d)
{ art_vdu(24);art_vduw(a);art_vduw(b);art_vduw(c);art_vduw(d);
}


int art_inkey(int n)
{
n=art_osbyte1(129,n);
if ((n & 0xFF00) == 0xFF00) return -1;
return n;
}

void art_mode(int n)
{ art_vdu(22);
  art_vdu(n);
}

/*
art_mouseX();
art_mouseY();
art_mouseB();
*/

void art_move(int x,int y)
{ art_vdu(25);art_vdu(4);
  art_vduw(x);art_vduw(y);
}

void art_moveby(int x,int y)
{ art_vdu(25);art_vdu(0);
  art_vduw(x);art_vduw(y);
}

/* mandel() ? */

void art_origin(int x,int y)
{ art_vdu(29);art_vduw(x);art_vduw(y);
}

void art_palette(int l,int p,int r,int g,int b)
{ art_vdu(19);art_vdu(l);art_vdu(p);art_vdu(r);art_vdu(g);art_vdu(b);
}

void art_plot(int n,int x,int y)
{ art_vdu(25);art_vdu(n);
  art_vduw(x);art_vduw(y);
}

int art_point(int x,int y)
{
short block[3];
block[0]=x;
block[1]=y;
block[2]=0;             /* to zero high byte */
x = (int)art_osword(9,block);
return block[2];
}

int art_pos()
{ return art_osbyte1(134,0) & 0xFF;
}

void art_rectangle(int x,int y,int l,int h)
{
art_move(x,y);
art_drawby(0,h);
art_drawby(l,0);
art_drawby(0,-h);
art_drawby(-l,0);
}

void art_rectanglefill(int x,int y,int l,int h)
{
art_move(x,y);
art_plot(0x61,l,h);
}

unsigned art_rnd(unsigned n)
{
extern unsigned rand(void);
return rand()%n+1;
}

void art_stringprint(char *s)
{
while (*s) art_vdu(*s++);
}

void art_tab(int x,int y) { art_vdu(31);art_vdu(x);art_vdu(y); }

void art_tint(int type, int mask)
{
        art_vdu(23);art_vdu(17);
        art_vdu(type & 3);
        art_vdu((mask << 6) & 0x0c0);
        art_vduw(0);art_vduw(0);art_vduw(0);
}

/*
** array of length of sequence for vdu codes
** it is assumed that the correct number of arguments has been supplied
*/

static char Qlen[32] =
{ 1,   /* VDU 0 */
  2,   /* next character to printer only */
  1,   /* printer on */
  1,   /* printer off */
  1,   /* print at text cursor */
  1,   /* print at graphics cursor */
  1,   /* enable VDU driver */
  1,   /* beep */
  1,   /* backspace */
  1,   /* forward space (horizontal tab) */
  1,   /* line feed */
  1,   /* up a line */
  1,   /* clear (text) screen */
  1,   /* carriage return */
  1,   /* page mode on */
  1,   /* page mode off */
  1,   /* clear graphics window */
  2,   /* define text colour */
  3,   /* define graphics colour */
  6,   /* define logical colour */
  1,   /* restore default palette */
  1,   /* disable VDU drivers */
  2,   /* Select screen mode */
  10,  /* VDU 23,.. */
  9,   /* set graphics window */
  6,   /* PLOT ... */
  1,   /* restore default windows */
  1,   /* ESCAPE char - no effect */
  5,   /* define text window */
  5,   /* define graphics origin */
  1,   /* home cursor */
  3    /* tab cursor */

/* and all the rest are 1 */
};

/*
** send the appropiate number of characters to art_vdu()
** it is assumed that the correct number of arguments has been supplied
*/


void art_vduq(int c,...)
{ va_list ap;
  int n;

  art_vdu(c);
  if (c>=' ') return;

  va_start(ap,c);
  n=Qlen[c];
  while(--n)
  { art_vdu(va_arg(ap,int));
  }
  va_end(ap);
}

int art_vpos()
{
    return art_osbyte1(134,0) >> 8;
}

/******************************************************************************

        Now for the new sound functions

******************************************************************************/

void art_sound(chan, amp, pitch, dur, futime)
int chan, amp, pitch, dur, futime;
{
        art_reg_set a;

        a.r[2] = (chan &0x0000ffff) | (amp << 16);
        a.r[3] = (pitch & 0x0000ffff) | (dur << 16);     /* compact bits */

        if(futime != -2) {
                a.r[0] = futime;
                a.r[1] = 0;
                a = art_swi(Sound_QSchedule, &a);
        }
        else
          a = art_swi(Sound_Sound, (art_reg_set *)(8 + (int)(&a))); /* fast! */

}

void art_sound_on()
{
        art_reg_set a;

        a.r[0] = 2;
        a = art_swi(Sound_Enable, &a);
}

void art_sound_off()
{
        art_reg_set a;

        a.r[0] = 1;
        a = art_swi(Sound_Enable, &a);
}

void art_voices(int chan)
{
        art_reg_set a;

        a.r[1] = a.r[2] = a.r[3] = a.r[4] = 0;
        a.r[0] = chan;
        a = art_swi(Sound_Configure, &a);
}

void art_stereo(int chan, int pos)
{
        art_reg_set a;

        a.r[0] = chan;
        a.r[1] = pos;
        a = art_swi(Sound_Stereo, &a);
}

void art_set_beats(int length)
{
        art_reg_set a;

        a.r[0] = length;
        a = art_swi(Sound_QBeats, &a);
}

int art_get_beats()
{
        art_reg_set a;

        a.r[0] = -1;
        a = art_swi(Sound_QBeats, &a);
        return a.r[0];
}

int art_get_beat()
{
        art_reg_set a;

        a.r[0] = 0;
        a = art_swi(Sound_QBeats, &a);
        return a.r[0];
}

void art_set_tempo(int newtemp)
{
        art_reg_set a;

        a.r[0] = newtemp;
        a = art_swi(Sound_QTempo, &a);
}

int art_get_tempo()
{
        art_reg_set a;

        a.r[0] = 0;
        a = art_swi(Sound_QTempo, &a);
        return a.r[0];
}


/******************************************************************************

        The WIMP functions - most of them in m/c in arthurasm for compactness

******************************************************************************/

int art_w_initialise(art_error * e)
{
        art_reg_set a;
        art_error * eo;

        eo = art_swix(Wimp_Initialise, &a);

        if((e->errnum = (int)eo) != 0)
                *e = *eo;
        return a.r[0];
}

int art_create_wind(art_wind_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_CreateWindow, &a);

        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}

int art_create_icon(art_icon_block *details, art_error * e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_CreateIcon, &a);

        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}


void art_delete_wind(int handle, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)&handle;
        eo = art_swix(Wimp_DeleteWindow, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_delete_icon(int wind, int icon, art_error *e)
{
        art_reg_set a;
        int i[2];
        art_error * eo;

        i[0] = wind;
        i[1] = icon;
        a.r[1] = (int)i;
        eo = art_swix(Wimp_DeleteIcon, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_open_wind(art_open_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_OpenWindow, &a);

        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_close_wind(int handle, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)&handle;
        eo = art_swix(Wimp_CloseWindow, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

int art_poll_wimp(int mask, art_univ_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[0] = mask;
        a.r[1] = (int)details;
        eo = art_swix(Wimp_Poll, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}

int art_redraw_wind(art_redraw_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_RedrawWindow, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}

int art_update_wind(art_redraw_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_UpdateWindow, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}

int art_get_rectangle(art_redraw_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_GetRectangle, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;

        return a.r[0];
}

void art_get_wind_state(int handle, art_open_block *out, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        out->wind_handle = handle;
        a.r[1] = (int)out;
        eo = art_swix(Wimp_GetWindowState, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_set_icon_state(art_istate_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_SetIconState, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_get_icon_state(art_istate_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_GetIconState, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_get_point_info(art_mouse_block *out, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)out;

        eo = art_swix(Wimp_GetPointerInfo, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_drag_box(art_drag_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;

        eo = art_swix(Wimp_DragBox, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_force_redraw(art_redraw_block *details, art_error *e)
{
        art_error * eo;
        eo = art_swix(Wimp_ForceRedraw, (art_reg_set *)details);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_set_caret_pos(art_caret_block *details, art_error *e)
{
        art_error * eo;
        eo = art_swix(Wimp_SetCaretPosition, (art_reg_set *)details);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_get_caret_pos(art_caret_block * out, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)out;

        eo = art_swix(Wimp_GetCaretPosition, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_create_menu(art_menu_block *details, int x, int y, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;
        a.r[2] = x;
        a.r[3] = y;

        eo = art_swix(Wimp_CreateMenu, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_decode_menu(art_menu_block *details,
                     art_univ_block *selections,
                     art_textbuf *out,
                     art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)details;
        a.r[2] = (int)selections;
        a.r[3] = (int)out;

        eo = art_swix(Wimp_DecodeMenu, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_which_icon(art_which_block *details, art_icon_list *out, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[0] = details->wind_handle;
        a.r[2] = details->bit_mask;
        a.r[3] = details->bit_set;

        a.r[1] = (int)out;

        eo = art_swix(Wimp_WhichIcon, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_set_extent(art_redraw_block *details, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[0] = details->wind_handle;
        a.r[1] = (int)details + 4;

        eo = art_swix(Wimp_SetExtent, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_set_point_shape(art_pshape_block *details, art_error *e)
{
        art_error * eo;
        eo = art_swix(Wimp_SetPointerShape, (art_reg_set *)details);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_open_template(char *name, art_error *e)
{
        art_reg_set a;
        art_error * eo;

        a.r[1] = (int)name;

        eo = art_swix(Wimp_OpenTemplate, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_close_template(art_error *e)
{
        art_reg_set a;
        art_error * eo;
        eo = art_swix(Wimp_CloseTemplate, &a);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}

void art_load_template(art_temp_block *details, art_error *e)
{
        art_error * eo;
        eo = art_swix(Wimp_LoadTemplate, (art_reg_set *)details);
        if((e->errnum = (int)eo) != 0)
                *e = *eo;
}


/*****************************************************************************/


/* in s.ArthurAsm ...
**  art_swi()
**  art_swix()
**  art_get()
**  art_vdu()
**  art_vduw()
**  art_mouseX()
**  art_mouseY()
**  art_mouseB()
*/