/*
 *  Deal w/ amiga console screen stuff (and other missing stuff - LJR).
 *
 *					-- luis soltero, 5/12/88 --
 *
 *  Total rework by Loren J. Rittle, 12/28/90
 *
 *  Now when ISpell is run in interactive mode, all screen
 *  I/O is directed at the CLI window ISpell is started in 
 *  if possible.  If started by WorkBench then, of course,
 *  a window is opened for screen I/O.
 *
 *  Note: None of the screen I/O routines are called if ISpell
 *  is run in ARexx server mode.
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <proto/all.h>
#include "version.h"
#include "ispell.h"

BPTR tty;

struct colortype
{
  char *style;
  char *frw;
  char *bak;
} colors[] =
{
#define WHITE_ON_BLACK	0
  {"0", "31", "42"},
#define WHITE_ON_BLUE	1
  {"0", "31", "40"},
#define BLACK_ON_WHITE	2
  {"0", "32", "41"},
#define BLUE_ON_WHITE	3
  {"0", "30", "41"},
#define ORANGE_ON_BLUE	4
  {"0", "33", "40"},
#define BLUE_ON_ORANGE  5
  {"0", "30", "43"}
};

#define SETCOLORS(x)	(setcolors(colors[x].style, colors[x].frw, colors[x].bak))

void setcolors (char *style, char *fg, char *bg)
{
  char buf[16];

  sprintf (buf, "\x9b%s\x3b%s\x3b%s\x6d", style, fg, bg);
  Write (tty, buf, strlen(buf));
}

void printcon (char *fmt,...)
{
  char buf[256];
  va_list ap;

  va_start (ap, fmt);
  vsprintf (buf, fmt, ap);
  va_end (ap);
  Write (tty, buf, strlen(buf));
}

void putccon (char ch)
{
  char c = ch;

  Write (tty, &c, 1);
}

int getccon (void)
{
  unsigned char ch;

  Read(tty, &ch,1L);
  return ((int)ch);
}

#undef GLOBAL
/* my version of BADDR() has no problems with casting */
#undef  BADDR
#define BADDR(x)        ((APTR)((long)x << 2))
#define MKBADDR(x)      ((BPTR)((long)x >> 2))

/* This subroutine does the work of turning the current console to raw  */
/* Pass a zero to turn it to cooked mode, any other value to turn it    */
/* to raw mode.                                                         */
long rawmode (int flag)
{
  long myargs[8];
  struct Process *proc;

  myargs[0] = flag ? DOSTRUE : DOSFALSE;

  proc = (struct Process *) FindTask (0L);
  return (sendpkt ((struct MsgPort *) proc->pr_ConsoleTask,
		   ACTION_SCREEN_MODE, myargs, 1));
}

LONG sendpkt (struct MsgPort *pid, LONG action, LONG args[], LONG nargs)
{
  struct MsgPort *replyport;
  struct StandardPacket *packet;

  LONG count, *pargs, res1;

  replyport = (struct MsgPort *) CreatePort (NULL, 0);
  if (!replyport)
    return (NULL);

  packet = (struct StandardPacket *)
    AllocMem ((long) sizeof (struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
  if (!packet)
    {
      DeletePort (replyport);
      return (NULL);
    }
  packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
  packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
  packet->sp_Pkt.dp_Port = replyport;
  packet->sp_Pkt.dp_Type = action;

  /* copy the args into the packet */
  pargs = &(packet->sp_Pkt.dp_Arg1);	/* address of first argument */
  for (count = 0; count < nargs; count++)
    pargs[count] = args[count];

  PutMsg (pid, (struct Message *) packet);	/* send packet */

  WaitPort (replyport);
  GetMsg (replyport);

  res1 = packet->sp_Pkt.dp_Res1;

  FreeMem ((char *) packet, (long) sizeof (struct StandardPacket));
  DeletePort (replyport);

  return (res1);
}

/* open a console window for ISpell */
void terminit (void)
{
  tty = Open("*", MODE_OLDFILE);
  rawmode(1);
  li = 23;
  co = 77;
}

void done (void)
{
  remove (tempfile);
  Close(tty);
  rawmode(0);
  exit (0);
}

/* clear the screen */
void erase (void)
{
  Write (tty, "\x0c", 1);
}

/* move to row, col */
void move (int row, int col)
{
  char buf[16];

  sprintf (buf, "\x9b%d\x3b%d\x48", row, col);
  Write (tty, buf, strlen(buf));
}

/* do stand out mode */
void inverse (void)
{
  SETCOLORS (BLUE_ON_WHITE);
}

/* do stand end mode */
void normal (void)
{
  SETCOLORS (WHITE_ON_BLUE);
}

/* do a back space */
void backup (void)
{
  putccon ('\b');
}

/* not implemented on the amiga */
void onstop (int signo)
{
}

void stop (void)
{
}

/*
 * i really do not understand why sleep is used in Ispell. Here is a null
 * function used soley to keep ispell happy.
 */
/* i do.  fixed.  -tgr */
void sleep (int n)
{
  if (n > 0)
    Delay (50L * n);
}

/*
 * This function is broken in SAS/C v5.10 - LJR 
 * Thanks to Matt Dillon, as this was lifted from DICE. 
 */
char *tmpnam(char *buf)
{
    static char Buf[32];
    static long i;

    if (buf == NULL)
	buf = Buf;
    sprintf(buf, "T:%08lx-%ld", FindTask(NULL), i++);
    return(buf);
}
