#include <exec/types.h>
#include <exec/io.h>
#include <devices/keymap.h>
#include <hardware/blit.h>
#include <graphics/text.h>
#include <graphics/sprite.h>
#include <graphics/rastport.h>
#include <intuition/intuition.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>

#include "main.h"

void reset(register struct console *con)
{
register struct so  *sop;
register USHORT     cnt;

con->gstat = ON;
con->tstat = 0;
con->stat = 0;
con->top = 1;
con->bot = rows;
con->row = 1;
con->col = 1;
for (cnt = 0; cnt < rows; cnt++) *(con->rows + cnt + 1) = 0;
con->attr = 0;
con->gset[0] = ASCII;
con->gset[1] = GRAPHICS;
con->gset[2] = SUPPLEMENTAL;
con->gset[3] = TECHNICAL;
setlset(con,0);
setrset(con,2);
con->s_row = con->row;
con->s_col = con->col;
con->s_attr = con->attr;
for (cnt = 0; cnt < SETS; cnt++)
    con->s_mset[cnt] = con->mset[cnt] = con->s_gset[cnt] = con->gset[cnt];
con->slset = con->s_lset = con->lset;
con->s_rset = con->rset;
con->s_tstat = con->tstat;
con->nstat = 0;
con->ordc = 0;
con->ordcol = 1;
setmem(con->tabs,COLUMNS,0);
for (cnt=0; cnt < COLUMNS; cnt+=8) con->tabs[cnt] = 1;
modifyattr(con);
showcursor(con);
SetRast(con->rp,BACKGROUND_PEN);
sop = &res;
while (sop != NULL) {
    if (sop->type == SO_SETUP) sop->active = FALSE;
    sop = sop->next;
    }
num.active = TRUE;
over.active = TRUE;
cret.active = TRUE;
trunc.active = TRUE;
mult.active = TRUE;
bit_8.active = TRUE;
curson.active = TRUE;
}

void cursorup(register struct console *con,USHORT cnt)
{
register UBYTE  *src,*dst;
USHORT          lines = 0;

while (cnt--) {
    if (con->row == con->top) {
        ScrollRaster(con->rp,0,-YSIZE,0,(con->top - 1) * YSIZE,
                                WIDTH-1,con->bot * YSIZE - 1);
        lines++;
        }
    else if (con->row > 1) con->row--;
    }
if (lines) {
    cnt = con->bot - con->top + 1;
    if (lines > cnt) lines = cnt;
    cnt -= lines;
    dst = con->rows + con->bot;
    src = con->rows + (con->bot - lines);
    while (cnt--) *dst-- = *src--;
    while (lines--) *dst-- = 0;
    }
}

void cursordown(register struct console *con,USHORT cnt)
{
register UBYTE  *src,*dst;
USHORT          lines = 0;

while (cnt--) {
    if (con->row == con->bot) {
        ScrollRaster(con->rp,0,YSIZE,0,(con->top - 1) * YSIZE,
                                WIDTH - 1,con->bot * YSIZE - 1);
        lines++;
        }
    else if (con->row < rows) con->row++;
    }
if (lines) {
    cnt = con->bot - con->top + 1;
    if (lines > cnt) lines = cnt;
    cnt -= lines;
    dst = con->rows + con->top;
    src = con->rows + (con->top + lines);
    while (cnt--) *dst++ = *src++;
    while (lines--) *dst++ = 0;
    }
}

void cursorleft(register struct console *con,register USHORT cnt)
{
while (cnt--) {
    if (con->col <= 1) {
        if (con->tstat & WRAP) cursoraboveline(con);
        }
    else con->col--;
    }
}

void cursorright(register struct console *con,register USHORT cnt)
{
while (cnt--) {
    if (con->col >= COLUMNS) {
        if (con->tstat & WRAP) cursornextline(con);
        }
    else con->col++;
    }
}

void cursornextline(register struct console *con)
{
con->col = 1;
cursordown(con,1);
}

void cursoraboveline(register struct console *con)
{
con->col = COLUMNS;
cursorup(con,1);
}

void hidecursor(register struct console *con)
{
SetRGB4(&con->scr->ViewPort,17 + (con->sp->num >> 1) * 4,0,0,0);
SetRGB4(&con->scr->ViewPort,18 + (con->sp->num >> 1) * 4,0,0,0);
SetRGB4(&con->scr->ViewPort,19 + (con->sp->num >> 1) * 4,0,0,0);
}

void showcursor(register struct console *con)
{
SetRGB4(&con->scr->ViewPort,17 + (con->sp->num >> 1) * 4,12,6,0);
SetRGB4(&con->scr->ViewPort,18 + (con->sp->num >> 1) * 4,12,12,12);
SetRGB4(&con->scr->ViewPort,19 + (con->sp->num >> 1) * 4,15,15,15);
}

void modifyattr(register struct console *con)
{
SetSoftStyle(con->rp,con->attr,FSF_BOLD|FSF_ITALIC|FSF_UNDERLINED);
}

void insertlines(register struct console *con,USHORT cnt)
{
register UBYTE  *src,*dst;
USHORT          lines = 0;

if ((con->row >= con->top)&&(con->row <= con->bot)) {
    if (cnt) {
        lines = con->bot - con->row;
        if (cnt > lines) cnt = lines;
        ScrollRaster(con->rp,0,-YSIZE * cnt,0,
                     (con->row - 1) * YSIZE,WIDTH - 1,con->bot * YSIZE - 1);
        lines -= cnt;
        dst = con->rows + con->bot + 1;
        src = con->rows + (con->bot - cnt);
        while (lines--) *dst-- = *src--;
        while (cnt--) *dst-- = 0;
        }
    }
}

void insertchars(register struct console *con,USHORT cnt)
{
USHORT y;

if (con->col < COLUMNS) {
    y = con->row * YSIZE;
    ScrollRaster(con->rp,-XSIZE * cnt,0,
                 (con->col - 1) * XSIZE,y - YSIZE,WIDTH - 1,y - 1);
    }
}

void deletechars(register struct console *con,USHORT cnt)
{
USHORT y;

if (con->col < COLUMNS) {
    y = con->row * YSIZE;
    ScrollRaster(con->rp,XSIZE * cnt,0,
                 (con->col - 1) * XSIZE,y - YSIZE,WIDTH - 1,y - 1);
    }
*(con->rows + con->row) = 0;
}

void deletelines(register struct console *con,USHORT cnt)
{
register UBYTE  *src,*dst;
USHORT          lines = 0;

if ((con->row >= con->top)&&(con->row <= con->bot)) {
    if (cnt) {
        lines = con->bot - con->row + 1;
        if (cnt > lines) cnt = lines;
        ScrollRaster(con->rp,0,YSIZE * cnt,0,
                     (con->row - 1) * YSIZE,WIDTH - 1,con->bot * YSIZE - 1);
        lines -= cnt;
        dst = con->rows + con->row;
        src = con->rows + (con->row + cnt);
        while (lines--) *dst++ = *src++;
        while (cnt--) *dst++ = 0;
        }
    }
}

void erasechars(register struct console *con,register USHORT cnt)
{
register USHORT col,y;

col = con->col + cnt - 1;
if (col > COLUMNS) col = COLUMNS;
y = con->row * YSIZE;
cleararea(con->rp,(USHORT)((con->col - 1) * XSIZE),
            (USHORT)(y - YSIZE),(USHORT)(col * XSIZE),y);
*(con->rows + con->row) = 0;
}

void eraselines(register struct console *con,register USHORT cnt)
{
register UBYTE  *dst = con->rows + con->row;
register USHORT row;

row = con->row + cnt;
if (row > rows) row = rows;
cleararea(con->rp,0,(USHORT)((con->row-1)*YSIZE),WIDTH,(USHORT)(row * YSIZE));
while (cnt--) *dst++ = 0;
}

void eraselinebeg(register struct console *con)
{
register USHORT y;

if (con->col > 1) {
    y = con->row * YSIZE;
    cleararea(con->rp,0,(USHORT)(y - YSIZE),(USHORT)(con->col * XSIZE),y);
    }
*(con->rows + con->row) = 0;
}

void erasescrbeg(register struct console *con)
{
register UBYTE  *dst = con->rows;
register USHORT cnt = con->row - 1;

if (con->row > 1) cleararea(con->rp,0,0,WIDTH,(USHORT)(cnt * YSIZE));
eraselinebeg(con);
while (cnt--) *(++dst) = 0;
}

void newline(register struct console *con)
{
cursornextline(con);
insertlines(con,1);
}

void cleararea(struct RastPort *rp,USHORT x1,USHORT y1,USHORT x2,USHORT y2)
{
ClipBlit(rp,x1,y1,rp,x1,y1,x2 - x1,y2 - y1,0);
}

void textout(register struct console *con)
{
register USHORT col = con->ordcol;
register SHORT  chars = con->ordc;
register UBYTE  width = *(con->rows + con->row);
register USHORT tcol;

if (width) {
    col <<= 1;
    col--;
    if (con->tstat & INSERT) {
        tcol = con->col;
        con->col = col;
        insertchars(con,(USHORT)(chars << 1));
        con->col = tcol;
        }
    }
else {
    if (con->tstat & INSERT) {
        tcol = con->col;
        con->col = col;
        insertchars(con,chars);
        con->col = tcol;
        }
    }
MOVE(con->rp,con->row,col);
if (con->attr & NEGATIVE) {
    SetAPen(con->rp,BACKGROUND_PEN);
    SetBPen(con->rp,FOREGROUND_PEN);
    Text(con->rp,con->ordtext,chars);
    SetAPen(con->rp,FOREGROUND_PEN);
    SetBPen(con->rp,BACKGROUND_PEN);
    }
else Text(con->rp,con->ordtext,chars);
if (width) {
    if (col + (chars << 1) > (COLUMNS+1)) chars = ((COLUMNS+1) - col) >> 1;
    if (chars > 0)
        stretch(con->rp,(col - 1) * XSIZE,(con->row - 1) * YSIZE,
                chars * XSIZE,YSIZE,width);
    }
con->ordc = 0;
}

void cursorout(register struct console *con)
{
USHORT col;

col = con->col;
if (col < 1) col = 1;
if (*(con->rows + con->row)) col <<= 1;
if (col > COLUMNS) col = COLUMNS;
if (con->ordc) textout(con);
MoveSprite(NULL,con->sp
            ,con->scr->LeftEdge + (col - 1) * (XSIZE / 2) - 2,
            con->scr->TopEdge + (con->row - 1) * YSIZE);
DRAWCURSOR(con->rp,&con->srp,con->row,col);
}
