#include <errno.h>
#include <stdio.h>
#include <sgtty.h>

/* Local vars */
int     OffY, LetterX, LetterY ;
static  int     Highlight = 0 ;
static  int     GrMode    = 0 ;

/* external vars */
int     WinX ;
int     WinY ;
int     Windowfd ;
int     MaxX, CurX ;
int     MaxY, CurY ;
int     CharX ;
int     CharY ;
int     Flag      = 0 ;

/* Opus board - vdi EDWIN c interface */
/*
        Something to remember is that all the vdi routines need to take
        16 bit integers, so remember to convert either before or after
        call as required.
*/

/* A few values that edwin has to remember */
typedef short INT16;     /*Define 16bit integer */

static INT16 RasterOp = 4;
static INT16 FillMode = 0;
static INT16 CCol = 15;
INT16 dev_handle;

INT16   savary51,
        savary52;

INT16   xheight,
        istring[2],
        gdms_err,
        xy[80],
        savary[64],
        xwidth,
        ywidth,
        cwidth,
        i, j,
        cheight;

static INT16    loc_xy[2] = {16000,10000};
static INT16    dloc_xy[2] = {0,0};

static char buf[8192];

/*
        Next bit is to set the screen to the right mode for text and
        graphics, since can't write normal text when in graphics mode
        and vice versa.
*/

#define TextMode 0
#define GraphicsMode 1

static int      ScreenMode = TextMode;

setgraphics()
{
        if (ScreenMode == TextMode) {
                ScreenMode = GraphicsMode;
                gdms_err = v_exit_cur(dev_handle);
        }
}

SetText()
{
        if (ScreenMode == GraphicsMode) {
                vdi_flush();
                gdms_err = v_enter_cur(dev_handle);
                ScreenMode = TextMode;
        }
}

static INT16 nominate[] = {1, 1, 1, 3, 1, 1, 1, 0,
                           0, 1, 0, 'D', 'I', 'S',
                           'P', 'L', 'A', 'Y', ' '};
static int   ScrDrive = 0;
static int   HighLightCol = 0;

static int   initialisededwin = 0;
static int   initialisedbefore = 0;

/* INT16 pelxy[4];
INT16 pel_array[0x20000]; */

EDWIN_DD_INIT (maxx, maxy)
        int *maxx, *maxy;
{
/* routine to initialise the screen for edwin use */
INT16   buf_size;

        /*
         * set the coordinate space to the funny one if using scrdrive package
         */
        if (initialisededwin != 0) return;
        initialisededwin = 1;
        if (HighLightCol == 0) {
                /*
                 * get the highlight colour
                 */
                HighLightCol = 4; /* Red */
                /* printf("Highlight colour : ");
                scanf("%d",&HighLightCol); */
        }
        if (ScrDrive == 1) {
                nominate[0] = 0;
        }
        /*
         * Set the defaults based on the values of the variables, in case
         * EDWIN has been reinitialised
         */
        nominate[2] = nominate[4] = nominate[6]  = nominate[9] = CCol;
                                                        /* Current colour */
        nominate[8] = FillMode;                         /* Fill style */
        buf_size = 2048;
        dev_handle = 0;
        vdi_open(dev_handle,buf,buf_size,0);/* start up vdi */
        gdms_err = v_opnwk(nominate,&dev_handle,savary);
                                        /* nominate the device */
        /* set the max values from what is returned by open workstation */
        WinX = savary[51]; WinY = savary[52];
        *maxx = WinX; *maxy = WinY;
        /* fprintf(stderr,"Dimensions of the screen are %d by %d\n",
                                savary[51],savary[52]); */
        setgraphics();
        init_input();
        /* gdms_err = TTGET(); */
        SetColourMap();
/*      pelxy[0] = pelxy[1] = 0;
        pelxy[2] = WinX;
        pelxy[3] = WinY;
        if (initialisedbefore != 0) {
                gdms_err = vswr_mode(dev_handle,4);
                gdms_err = v_put_npels(dev_handle,pelxy,pel_array,0x20000);
                if (gdms_err != 0) {
                        fprintf(stderr,"gdms_err = %d\n",gdms_err);
                        gdms_err = vq_error();
                        fprintf(stderr,"Error is %d\n",gdms_err);
                }
        }
        initialisedbefore = 1; */
        gdms_err = vswr_mode(dev_handle,RasterOp);      /* Raster mode */
}

EDWIN_DD_UPDATE ()
{
        vdi_flush();
}

EDWIN_DD_CLEAR ()
{
                                        /* clear the screen area */
        setgraphics();
        gdms_err = v_clrwk(dev_handle);
}

EDWIN_DD_DOT (x, y)
        int x, y;
{
        /* Draw a dot at the point */
        setgraphics();
        xy[0] = x; xy[1] = y;
        gdms_err = v_pmarker(dev_handle,1,xy);
}

EDWIN_DD_LINE (ox,oy,nx,ny)
        int ox,oy,nx,ny;
{
                                        /* draw a line */
        /* keep it simple just now */
        setgraphics();
        xy[0] = ox; xy[1] = oy;
        xy[2] = nx; xy[3] = ny;
        gdms_err = v_pline(dev_handle,2,xy);
}

outofrange(x,y)
        int     x,y;
{
        if ((x < 0) || (x > WinX)) return(1);
        if ((y < 0) || (y > WinY)) return(1);
        return(0);
}

EDWIN_DD_RECT(lx,ly,nx,ny)
        int lx,ly,nx,ny;
{
                                        /* draw a rectangle */
        if ((outofrange(lx,ly) == 1) || (outofrange(nx,ny) == 1)) {
                /* fprintf(stdout,"Rectangle %d %d %d %d out of range \n",
                        lx,ly,nx,ny); */
                return;
        }
        setgraphics();
        xy[0] = xy[2] = xy[8] = lx;     /* left x coord */
        xy[1] = xy[7] = xy[9] = ly;     /* bottom y coord */
        xy[4] = xy[6] = nx;             /* right x coord */
        xy[3] = xy[5] = ny;             /* top y coord */
        if (FillMode == 0)
                gdms_err = v_pline(dev_handle,5,xy);
        else
                gdms_err = v_fillarea(dev_handle,5,xy);
}

EDWIN_DD_POLY(count,xs,ys)
        int count;
        int xs[], ys[];
{
                                                        /* draw a polygon */
        int i;
        INT16 c;

        setgraphics();
        for (i = 0 ; i < count ; i ++ ) {
                if (outofrange(xs[i],ys[i]) == 1) return;
                xy[i * 2] = xs[i];
                xy[(i * 2) + 1] = ys[i];
        }
        c = count;
        if (FillMode == 0)
                gdms_err = v_pline(dev_handle,c,xy);    /* outline polygon */
        else
                gdms_err = v_fillarea(dev_handle,c,xy); /* filled polygon */
}

EDWIN_DD_TEXT(sx,sy,ch)
        int sx,sy;
        char *ch;
{
                                        /* write some text out */
        char str[80];
        INT16 attribs[10];

        /* gdms_err = vqt_attributes(dev_handle,attribs);
        fprintf(stderr,"Colour is %d. Write mode is %d\n",
                        attribs[1],attribs[5]); */

        setgraphics();
        if (outofrange(sx,sy) == 1) {
                /* sprintf(str,"Text at %d %d %s",sx,sy,ch);
                gdms_err = v_gtext(dev_handle,1000,1000,str);
                fprintf(stderr,"Text at %d %d %s\n",sx,sy,ch); */
        }
/*      gdms_err = vswr_mode(dev_handle,8); */
        gdms_err = v_gtext(dev_handle,sx,sy,ch);
        if (RasterOp == 2) gdms_err = vswr_mode(dev_handle,RasterOp);
}

/* static int ColTable[] = {0, 1, 1, 3, 2}; */

static  int ColTable[] = {0, 15, 4, 1, 2, 6, 8, 5,
                          10, 3, 7, 9, 11, 12, 13, 14};

static INT16 red[] = {0, 0, 1000, 1000, 0, 0, 1000, 666,
                      1000, 666, 1000, 1000, 0, 333, 666, 1000};

static INT16 green[] = {0, 1000, 0, 333, 0, 1000, 0, 666,
                        1000, 1000, 333, 666, 666, 333, 0, 1000};

static INT16 blue[] = {0, 0, 0, 0, 1000, 1000, 1000, 666,
                        0, 666, 0, 666, 0, 1000, 0, 1000};

SetColourMap()
{
        int i;
        INT16 i16;
        INT16 rgb[3], realise[3];

        for (i = 0; i < 16 ; i ++) {
                i16 = i;
                rgb[0] = red[i];
                rgb[1] = green[i];
                rgb[2] = blue[i];
                gdms_err = vs_color(dev_handle,i16,rgb,realise);
        }
}

EDWIN_DD_COL (Colnum)
        int Colnum;
{
        int tcol;

        CCol = ColTable[Colnum];
        gdms_err = vsf_color(dev_handle,CCol);  /* set the fill colour */
        gdms_err = vsl_color(dev_handle,CCol);  /* set the line colour */
        /* Make sure that text is always printed out, readably */
        if (CCol == 0)
                tcol = 15;
        else
                tcol = CCol;
        gdms_err = vst_color(dev_handle,tcol);  /* ste the text colour */
}

static int OpMap[] = {4, 2, 8, 10, 11};  /* magic numbers - see page 4 - 114 */

EDWIN_DD_MODE (Mode)
        int Mode;
{
        /* Setting the raster operation mode */
        RasterOp = OpMap[Mode];
        gdms_err = vswr_mode(dev_handle,RasterOp);
}

EDWIN_DD_FILL(Mode)
        int Mode;
{
        FillMode = Mode;
        gdms_err = vsf_interior(dev_handle,FillMode);
}

EDWIN___B_SAM (state,x,y)
        int *state, *x, *y;
{
        /* sample cursor events etc. */
        INT16 choice;
        char str[8];

        EDWIN___B_REQ(state,x,y);
        return;
        setgraphics();
        gdms_err = v_dspcur(dev_handle,loc_xy[0],loc_xy[1]);
        gdms_err = vsm_locator(dev_handle,loc_xy);
        *x = loc_xy[0] ; *y = loc_xy[1];
        gdms_err = vsm_string(dev_handle,2,0,dloc_xy,str);
        if (gdms_err == -1) {
                fprintf("Error calling vsm_string\n");
        } else if (gdms_err == 0) {
                choice == 0;
        } else {
                choice = str[0];
                *x = dloc_xy[0]; *y = dloc_xy[1];
        }
        /* gdms_err = vsm_choice(dev_handle,1,&choice); */
        if (choice != 0)
                *state = choice;
        else
                *state = 0;
        /* if (loc_xy[0] == loc_xy[1] == 0) *state = 3; */
        if (*state != 0) gdms_err = v_rmcur(dev_handle);
}

EDWIN___B_REQ (state,x,y)
        int *state, *x, *y;
{
        INT16 choice[2];
        INT16 nloc_xy[2];
        int choicei;
        char c[20];

        setgraphics();
        gdms_err = vrq_locator(dev_handle,loc_xy,0,0,dev_handle,
                                nloc_xy,choice);
        if (gdms_err == 0) {
                /* request unsuccessful */
                fprintf(stderr,"Request locator unsuccessful\n");
                EDWIN_DD_TEXT(4000,4000,'0');
        }
        else if (gdms_err == -1) {
                /* Error */
                choice[0] = vq_error();
                EDWIN_DD_TERM();
                choicei = choice[0];
                fprintf(stderr,"Error is %d\n",choicei);
                exit(0);
        }
        *x = nloc_xy[0]; *y = nloc_xy[1];
        loc_xy[0] = nloc_xy[0];
        loc_xy[1] = nloc_xy[1];
        choicei = choice[0];
        choicei = choicei & 255;
        *state = choicei;
        /* sprintf(c,"%c %d",choicei,choicei);
        EDWIN_DD_TEXT(*x,*y,c); */
        if (choicei == 3) {
                /* stop on control C */
                EDWIN_DD_TEXT(*x,*y,"Terminating EDWIN");
                EDWIN_DD_TERM();
                printf("Terminating EDWIN\n");
                exit(0);
        }
}

static INT16 echo_xy[2] = {0,0};
static char ins[80];

/*
EDWIN_SCREEN_TTGET ()
{
        int i;
        INT16 maxlen,echo;
        char errstr[80];

        /* get keyboard input only */
        /* must use the sample routine instead of the request routine
           because the request routine waits for cr */

/*        EDWIN_DD_UPDATE;
        setgraphics();
        echo_xy[0] = CurX * CharX;
        echo_xy[1] = WinY - (CurY * CharY);
        maxlen = 79; echo = 0;
        if (strlen(ins) >= 1) {
                for (j = 0;j < strlen(ins);j ++) {
                        ins[j] = ins[j + 1];
                }
                i = ins[0];
                ins[strlen(ins)] = 0;
                if (strlen(ins) == 0) return(13);
                return(i);
        }
        while (1) {
                ins[0] = '*'; ins[1] = 0;
                gdms_err = vrq_string(dev_handle,maxlen,echo,
                                echo_xy,ins);  
                if (gdms_err < 0) {
                        if (gdms_err < 0)
                                EDWIN_DD_TEXT(0,1000,"TTGET error");
                        continue;
                }
                if (strlen(ins) == 0) return(13);
                ins[strlen(ins)] = 13;
                ins[strlen(ins) + 1] = 0;  /* stick a carriage return on end */
/*                i = ins[0];
                return(i);
        }
}
*/

/*
 * New ttget function
 */

static  int     dev_channel;
struct  sgttyb  dev_org_parm, dev_cur_parm;
static  int     dev_status;
static  int     input_init = 0;
#define CBREAK  RAW

init_input()
{
        short x;

        if (input_init != 0) return;
        input_init = 1;
        dev_channel = open("/dev/tty",2);
        dev_status = gtty(dev_channel,&dev_org_parm);
        dev_cur_parm = dev_org_parm;
        /* set up the mask */
        /* turn off echo */
        x = !ECHO; dev_cur_parm.sg_flags &= x;
        /* set raw on */
        x = (RAW | CRMOD);
        dev_cur_parm.sg_flags |= x;
        stty(dev_channel,&dev_cur_parm);
}

shut_input()
{
        /* end of input or quit */
        input_init = 0;
        stty(dev_channel,&dev_org_parm);
}

SetParm(Parm,OnOff)
        int Parm, OnOff;
{
        int cur;

        cur = dev_cur_parm.sg_flags & Parm;
        if (OnOff == 0) {
                if (cur == 0) return;
                dev_cur_parm.sg_flags = dev_cur_parm.sg_flags & (!Parm);
        } else {
                if (cur != 0) return;
                dev_cur_parm.sg_flags = dev_cur_parm.sg_flags | Parm;
        }
        cur = stty(dev_channel, &dev_cur_parm);
}

EDWIN_SCREEN_TTGET()
{
        char ch;
        int i,status;

        init_input();
        status = read(dev_channel,&ch,1);
        i = ch;
        if ((i == 4) || (i == 3) || (i == 26)) { 
                shut_input();
        }
        return(i);
}

EDWIN_DD_TERM()
{
        int i;

        /* save the screen */
/*      i = v_get_npels(dev_handle,pelxy,pel_array,0x20000);
        if (i < 0) i = vq_error(); */
        SetText();
        gdms_err = v_enter_cur(dev_handle);
        gdms_err = v_clswk(dev_handle);
        if (input_init != 0) shut_input();
        vdi_close();
        initialisededwin = 0;
        printf("\n");
        /* printf("Get pels returned %d\n",i); */
}

static int  initialisedscreen = 0;

InitScreen(argc , argv)
        int argc ;
        char **argv ;
{
        /* Ignore parameters */

        if (initialisedscreen != 0) return;
        CurX = CurY = 0 ;

        CharX = 410;
        CharY = 1311;
        /* OffY  = 300; */
        LetterX = 359;
        LetterY = 843;
        OffY = CharY - LetterY - 200;
        ScrDrive = 1;       /* set the scr drive flag for the different
                             * coordinate set. This is supposed to be so that
                             * the scrdrive package will work on all manner of
                             * odd screen types ?
                             */
        EDWIN_DD_INIT(&WinX,&WinY);
        EDWIN_DD_FILL(1);
        MaxX = 79;
        MaxY = 23;
        WinX = 32767;
        WinY = 31456;
        CurX = CurY = 0;
}

KillWindow()
{
        EDWIN_DD_TERM();
        initialisedscreen = 0;
        exit(0) ; 
}

InitEvents()
{
}

TTGET()
{
        int ch;

        ch = EDWIN_SCREEN_TTGET();
        return(ch);
}

TTGet()
{
        int ch;

        ch = EDWIN_SCREEN_TTGET();
        /* EDWIN_DD_TEXT(0,10000,"TTGET has returned"); */
        return(ch);
}

PrGraph(Ch) 
        char    *Ch ;
{
        int     X, Y ;

        while (*Ch != '\0') {
                switch (*Ch) {

                       case 'j': {*Ch = 217; break;}
                       case 'k': {*Ch = 191; break;}
                       case 'l': {*Ch = 218; break;}
                       case 'm': {*Ch = 192; break;}
                       case 'n': {*Ch = 197; break;}
                       case 'q': {*Ch = 196; break;}
                       case 't': {*Ch = 195; break;}
                       case 'u': {*Ch = 180; break;}
                       case 'v': {*Ch = 193; break;}
                       case 'w': {*Ch = 194; break;}
                       case 'x': {*Ch = 179; break;}
                       default: {}

                } ;

                Ch ++;
        }
}

TTString (Ch)
        char *Ch ;
{
        int X, Y ;

        if (GrMode == 1) PrGraph(Ch);

        X = CurX * CharX ;
        Y = CurY * CharY - OffY;
        Y = WinY - Y;

        if (Highlight == 1)
                vst_color(dev_handle,ColTable[HighLightCol]);
        EDWIN_DD_TEXT(X, Y, Ch);
        vst_color(dev_handle,CCol);

        MoveTo(CurX + strlen(Ch), CurY);
}

TTPUT (Ch)
        int Ch ;
{
        TTPut(Ch);      /* Dummy call from SCRDRIVE stuff */
}

TTPut (Ch)
        int Ch ;
{
        int X, Y ;
        char str[2];

        if (Ch == 8) {
                /* Back space hasa funny character associated with it
                 * so filter it out and move the cursor instead
                 */
                if (CurX > 0) MoveTo(CurX - 1,CurY);
        } else {
                str[0] = Ch;
                str[1] = 0;
                TTString(str);
        }
}

cursor()
{
        /* same routine is needed to put the cursor in as take it out again. */
        int x, y, x1, y1;

        x = CurX * CharX;
        y = WinY - (CurY * CharY) + OffY;
        x1 = x + LetterX;
        y1 = y + LetterY;
        EDWIN_DD_MODE(4);
        EDWIN_DD_RECT(x, y, x1, y1);
        EDWIN_DD_MODE(0);
}

DrawCursor()
{ 
        cursor();
}

DeleteCursor()
{ 
        cursor();
}

Rectangle(X, Y, W, H)
        int X, Y, W, H;
{
        int Y1;

        Y1 = Y + H;
        Y1 = WinY - Y1 + (CharY / 2) + OffY;
        Y = WinY - Y + (CharY / 2) + OffY;
        EDWIN_DD_MODE(0);
        gdms_err = vsf_color(dev_handle,ColTable[1]);
        EDWIN_DD_RECT(X, Y, X + W, Y1);
        gdms_err = vsf_color(dev_handle,CCol);
}

DrawLine(X, Y, X1, Y1)
        int X, Y, X1, Y1 ;
{
        Y = WinY - Y + (CharY / 2) + OffY;
        Y1 = WinY - Y1 + (CharY / 2) + OffY;
        gdms_err = vsl_color(dev_handle,ColTable[1]);
        EDWIN_DD_LINE(X, Y, X1, Y1);
        gdms_err = vsl_color(dev_handle,CCol);
}

FLUSHOUTPUT()
{
        EDWIN_DD_UPDATE();      /* Scrdrive link */
}

FlushOutput ()
{
        EDWIN_DD_UPDATE();
}

ClearLineBlt (Start, Lines)
        int Start, Lines ;
{ 
        int x, y, x1, y1;
        int dummyWinY;

        x = 0 ;
        y = WinY - ((Start - Lines) * CharY) ;

        x1 = WinX;
        y1 = WinY - (Start * CharY);
        gdms_err = vswr_mode(dev_handle,1);
        if (y > 32767) y = 32767;
        dummyWinY = WinY; WinY = WinX;  /* to keep the stuff in range and
                                         * be able to delete the top line
                                         * Terribly hacky.
                                         */
        EDWIN_DD_RECT(x, y, x1, y1);
        WinY = dummyWinY;
        gdms_err = vswr_mode(dev_handle,RasterOp);
}

ScrollBlt ( Low, High, Size )
        int Low, High, Size ;
{
        int    dx, dy, w, h, sx, sy ;
        INT16 xy[6];
        int ssize;

        sx  = 0 ; 
        sy  = 0 ;

        xy[0] = xy[4] = 0; xy[2] = WinX;
        gdms_err = vswr_mode(dev_handle,4);
        if (Size > 0) {
                /*
                 * Text moving down
                 */
                ssize = High - Low - Size;
                xy[1] = WinY - ((High - Size) * CharY);
                xy[3] = WinY - ((Low - 1) * CharY);
                xy[5] = WinY - ((High) * CharY);
                v_copy_pels(dev_handle,xy);
                ClearLineBlt(Low + Size - 1,Size);
        } else if (Size < 0) {
                /*
                 * Text moving up
                 */
                Size = -Size;
                ssize = High - Low - Size + 1;
                xy[1] = WinY - ((High) * CharY);
                xy[3] = WinY - ((High - ssize) * CharY);
                xy[5] = WinY - ((High - Size) * CharY);
                v_copy_pels(dev_handle,xy);
                ClearLineBlt(High, Size) ;
        }
}

ClearScreen ()
{ 
        EDWIN_DD_CLEAR();
}


ClearLine() 
{
        ClearLineBlt(CurY, 1) ;
}

Home ()
{
        CurX = 0 ;
        CurY = 0;
}

SCR_MOVE_TO( X , Y )
        int X, Y ;
{
        MoveTo( X , Y );        /* Scrdrive linkage */
}

MoveTo ( X , Y ) 
        int X, Y ;
{
        if (X > MaxX)
                X = MaxX ;
        else if (X < 0)
                X = 0 ;

        if (Y > MaxY)
                Y = MaxY ;
        else if (Y < 0)
                Y = 0 ;

        CurX = X ; 
        CurY = Y ;
}

ScrollUp ( N )
        int N ;
{
        ScrollBlt(0, MaxY, -N) ;
}

ScrollDown ( N )
        int N ;
{ 
        ScrollBlt(0, MaxY, N) ;
}

Scroll ( LLn, HLn, By ) 
        int LLn, HLn, By ;
{ 
        ScrollBlt(LLn, HLn, By) ;
}

DownLine ()
{ 
        if (CurY < MaxY)
                CurY = CurY + 1;
}

UpLine ()
{
        if (CurY > 0) {
                CurY = CurY - 1 ;
        }
}

SCR_SET_INTENSITY ( LoHi )
        int LoHi;
{
        SetIntensity ( LoHi );  /* Scrdrive linkage */
}

SetIntensity ( LoHi )
        int LoHi ;
{ 
        if (LoHi != Highlight)
                Highlight = LoHi ;
}

SetGraphics ( Mode )
        int Mode ;
{
if (GrMode != Mode)
        GrMode = Mode ;
}

sigwinch()
{
        Flag = 1 ; 
}

refresh()
{
Flag = 0 ;
}

