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

#include "main.h"

char    posreq[]    = "\x9B%d;%dR";
char    primda[]    = "\x9B?62;9c";
char    secda[]     = "\x9B>1;10;0c";
char    tstat[]     = "\x9B""0n";
char    pstat[]     = "\x9B?13n";
char    ustat[]     = "\x9B?21n";
char    klang[]     = "\x9B?27;6n";

interpret(register struct console *con,register LONG len)
{
register SHORT  cnt,lim;
register char   *scp;
char            c,com[16];

scp = con->buf;
while (len--) {
    c = *scp++;
    if (con->stat) {
        cnt = con->stat;
        con->stat = 0;
        switch (cnt) {
            case SEQ_ESC:
                switch (c) {
                    case '[':
                        con->stat = SEQ_CSI;
                        con->argi = 0;
                        con->carg = 0;
                        break;
                    case '#':
                        con->stat = SEQ_LWIDTH;
                        break;
                    case 'P':
                        con->stat = SEQ_DCS;
                        break;
                    case ' ':
                        con->stat = SEQ_SPC;
                        break;
                    case '(':
                        con->stat = SEQ_G0;
                        break;
                    case ')':
                        con->stat = SEQ_G1;
                        break;
                    case '*':
                        con->stat = SEQ_G2;
                        break;
                    case '+':
                        con->stat = SEQ_G3;
                        break;
                    case '~':
                        setrset(con,1);
                        break;
                    case 'n':
                        setlset(con,2);
                        break;
                    case '}':
                        setrset(con,2);
                        break;
                    case 'o':
                        setlset(con,3);
                        break;
                    case '|':
                        setrset(con,3);
                        break;
                    case 'N':
                        con->slset = con->lset;
                        con->tstat |= GXGL;
                        setlset(con,2);
                        break;
                    case 'O':
                        con->slset = con->lset;
                        con->tstat |= GXGL;
                        setlset(con,3);
                        break;
                    case '<':
                    case '=':
                        keypadmode(TRUE);
                        activate(&appl);
                        break;
                    case '>':
                        keypadmode(FALSE);
                        activate(&num);
                        break;
                    case 'D':
                        cursordown(con,1);
                        break;
                    case 'M':
                        cursorup(con,1);
                        break;
                    case 'E':
                        cursornextline(con);
                        break;
                    case '7':
                        con->s_row = con->row;
                        con->s_col = con->col;
                        con->s_attr = con->attr;
                        for (cnt = 0; cnt < SETS; cnt++) {
                            con->s_gset[cnt] = con->gset[cnt];
                            con->s_mset[cnt] = con->mset[cnt];
                            }
                        con->s_lset = con->lset;
                        con->s_rset = con->rset;
                        con->s_tstat = con->tstat;
                        break;
                    case '8':
                        if (con->ordc) textout(con);
                        con->row = con->s_row;
                        con->col = con->s_col;
                        con->attr = con->s_attr;
                        for (cnt = 0; cnt < SETS; cnt++) {
                            con->gset[cnt] = con->s_gset[cnt];
                            con->mset[cnt] = con->s_mset[cnt];
                            }
                        setlset(con,con->s_lset);
                        setrset(con,con->s_rset);
                        con->tstat = con->s_tstat &
                            (WRAP | INSERT | NEWLINE | CONVERT | CURSOR);
                        if (con->tstat & WRAP) activate(&wrap);
                        else activate(&trunc);
                        if (con->tstat & INSERT) activate(&ins);
                        else activate(&over);
                        if (con->tstat & NEWLINE) {
                            entermode(TRUE);
                            activate(&newl);
                            }
                        else {
                            entermode(FALSE);
                            activate(&cret);
                            }
                        if (con->tstat & CONVERT) activate(&bit_7);
                        else activate(&bit_8);
                        modifyattr(con);
                        break;
                    case 'H':
                        con->tabs[con->col] = 1;
                        break;
                    case 'c':
                        reset(con);
                        break;
                    case 'Z':
                        sendstring(con,primda);
                        break;
                    default: ;
                    }
                break;
            case SEQ_CSI:
                if (isdigit(c)) {
                    con->carg = con->carg * 10;
                    con->carg += (USHORT)(c - '0');
                    con->stat = SEQ_CSI;
                    }
                else {
                    switch (c) {
                        case ';':
                            con->args[con->argi] = con->carg;
                            con->carg = 0;
                            con->argi++;
                            if (con->argi > ARGUMENTS)
                                con->argi = ARGUMENTS;
                            con->stat = SEQ_CSI;
                            break;
                        case '?':
                            con->stat = SEQ_MOD;
                            break;
                        case '>':
                            con->stat = SEQ_SEC;
                            break;
                        case '!':
                            con->stat = SEQ_RES;
                            break;
                        case '"':
                            con->stat = SEQ_SET;
                            break;
                        case '\x27':
                        case '^':
                            con->stat = SEQ_ONE;
                            break;
                        case 'h':
                            switch (con->carg) {
                                case 2:
                                    con->gstat |= LOCKED;
                                    break;
                                case 4:
                                    if (con->ordc) textout(con);
                                    con->tstat |= INSERT;
                                    activate(&ins);
                                    break;
                                case 20:
                                    entermode(TRUE);
                                    con->tstat |= NEWLINE;
                                    activate(&newl);
                                    break;
                                default: ;
                                }
                            break;
                        case 'l':
                            switch (con->carg) {
                                case 2:
                                    con->gstat &= (MASK - LOCKED);
                                    break;
                                case 4:
                                    if (con->ordc) textout(con);
                                    con->tstat &= (MASK - INSERT);
                                    activate(&over);
                                    break;
                                case 20:
                                    entermode(FALSE);
                                    con->tstat &= (MASK - NEWLINE);
                                    activate(&cret);
                                    break;
                                default: ;
                                }
                            break;
                        case 'A':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            cursorup(con,cnt);
                            break;
                        case 'B':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            cursordown(con,cnt);
                            break;
                        case 'C':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            cursorright(con,cnt);
                            break;
                        case 'D':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            cursorleft(con,cnt);
                            break;
                        case 'f':
                        case 'H':
                            if (con->ordc) textout(con);
                            if (con->argi) con->row = con->args[0];
                            else con->row = con->carg;
                            if (con->row == 0) con->row = 1;
                            if (con->row > rows) con->row = rows;
                            if ((con->argi)&&(con->carg)) {
                                con->col = con->carg;
                                if (con->col > COLUMNS) con->col = COLUMNS;
                                }
                            else con->col = 1;
                            break;
                        case 'g':
                            if (con->carg == 0) con->tabs[con->col] = 0;
                            if (con->carg == 3) setmem(con->tabs,COLUMNS,0);
                            break;
                        case 'm':
                            if (con->ordc) textout(con);
                            con->args[con->argi] = con->carg;
                            con->argi++;
                            for (cnt = 0; cnt < con->argi; cnt++) {
                                switch(con->args[cnt]) {
                                    case 0:  con->attr= 0;
                                             break;
                                    case 1:  con->attr|=FSF_BOLD;
                                             break;
                                    case 3:  con->attr|=FSF_ITALIC;
                                             break;
                                    case 4:  con->attr|=FSF_UNDERLINED;
                                             break;
                                    case 7:  con->attr|=NEGATIVE;
                                             break;
                                    case 22: con->attr&=(MASK-FSF_BOLD);
                                             break;
                                    case 23: con->attr&=(MASK-FSF_ITALIC);
                                             break;
                                    case 24: con->attr&=(MASK-FSF_UNDERLINED);
                                             break;
                                    case 27: con->attr&=(MASK-NEGATIVE);
                                             break;
                                    default:    ;
                                    }
                                }
                            modifyattr(con);
                            break;
                        case 'L':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            insertlines(con,cnt);
                            break;
                        case 'M':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            deletelines(con,cnt);
                            break;
                        case '@':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            insertchars(con,cnt);
                            break;
                        case 'P':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            deletechars(con,cnt);
                            break;
                        case 'X':
                            cnt = con->carg;
                            if (cnt == 0) cnt = 1;
                            erasechars(con,cnt);
                            break;
                        case 'K':
                            switch (con->carg) {
                                case 0:
                                    erasechars(con,
                                        (USHORT)((COLUMNS + 1) - con->col));
                                    break;
                                case 1:
                                    eraselinebeg(con);
                                    break;
                                case 2:
                                    eraselinebeg(con);
                                    erasechars(con,
                                        (USHORT)((COLUMNS + 1) - con->col));
                                    break;
                                default:    ;
                                }
                            break;
                        case 'J':
                            switch (con->carg) {
                                case 0:
                                    if (con->row < rows) {
                                        if (con->ordc) textout(con);
                                        con->row++;
                                        eraselines(con,
                                            (USHORT)(rows - con->row));
                                        con->row--;
                                        }
                                    erasechars(con,
                                        (USHORT)((COLUMNS + 1) - con->col));
                                    break;
                                case 1:
                                    erasescrbeg(con);
                                    eraselinebeg(con);
                                    break;
                                case 2:
                                    SetRast(con->rp,BACKGROUND_PEN);
                                    for (cnt = 0; cnt < rows; cnt++)
                                        *(con->rows + cnt + 1) = 0;
                                    break;
                                default:    ;
                                }
                            break;
                        case 'r':
                            if (con->ordc) textout(con);
                            if ((con->argi)&&(con->carg))
                                con->bot = con->carg;
                            else con->bot = rows;
                            if (con->argi) con->top = con->args[0];
                            else con->top = con->carg;
                            if (con->top == 0) con->top = 1;
                            con->row = 1;
                            con->col = 1;
                            break;
                        case 'c':
                            if (con->carg == 0) sendstring(con,primda);
                            break;
                        case 'n':
                            switch (con->carg) {
                                case 5: sendstring(con,tstat);
                                        break;
                                case 6: sprintf(com,posreq,con->row,con->col);
                                        sendstring(con,com);
                                        break;
                                default:    ;
                                }
                            break;
                        default:    ;
                        }
                    }
                break;
            case SEQ_MOD:
                if (isdigit(c)) {
                    con->carg = con->carg * 10;
                    con->carg += (USHORT)(c - '0');
                    con->stat = SEQ_MOD;
                    }
                else {
                    switch (c) {
                        case ';':
                            con->args[con->argi] = con->carg;
                            con->carg = 0;
                            con->argi++;
                            if (con->argi > ARGUMENTS)
                                con->argi = ARGUMENTS;
                            con->stat = SEQ_MOD;
                            break;
                        case 'h':
                            switch (con->carg) {
                                case 1:
                                    cursormode(FALSE);
                                    break;
                                case 7:
                                    con->tstat |= WRAP;
                                    activate(&wrap);
                                    break;
                                case 25:
                                    showcursor(con);
                                    activate(&curson);
                                    break;
                                case 42:
                                    con->nstat |= NATIONAL;
                                    setlset(con,con->lset);
                                    setrset(con,con->rset);
                                    activate(&nat);
                                    modifyattr(con);
                                    break;
                                default: ;
                                }
                            break;
                        case 'l':
                            switch (con->carg) {
                                case 1:
                                    cursormode(TRUE);
                                    break;
                                case 7:
                                    con->tstat &= (MASK - WRAP);
                                    activate(&trunc);
                                    break;
                                case 25:
                                    hidecursor(con);
                                    activate(&cursoff);
                                    break;
                                case 42:
                                    con->nstat &= (MASK - NATIONAL);
                                    setlset(con,con->lset);
                                    setrset(con,con->rset);
                                    activate(&mult);
                                    modifyattr(con);
                                    break;
                                default: ;
                                }
                            break;
                        case 'n':
                            switch (con->carg) {
                                case 15:    sendstring(con,pstat);
                                            break;
                                case 25:    sendstring(con,ustat);
                                            break;
                                case 26:    sendstring(con,klang);
                                            break;
                                default: ;
                                }
                            break;
                        }
                    }
                break;
            case SEQ_LWIDTH:
                if (*(con->rows + con->row)) break;
                switch (c) {
                    case '3':   *(con->rows + con->row) = UPPER_SIDE;
                                break;
                    case '4':   *(con->rows + con->row) = LOWER_SIDE;
                                break;
                    case '6':   *(con->rows + con->row) = HORIZ_ONLY;
                                break;
                    default:    ;
                    }
                if (*(con->rows + con->row)) {
                    if (con->ordc) textout(con);
                    stretch(con->rp,0,(con->row - 1) * YSIZE,
                            WIDTH / 2,YSIZE,*(con->rows + con->row));
                    }
                break;
            case SEQ_SET:
                if (c == 'p') {
                    if (con->args[0] == 62) {
                        if (con->argi == 0) {
                            con->tstat &= (MASK - CONVERT);
                            activate(&bit_8);
                            }
                        else {
                            if (con->args[1] == 1) {
                                con->tstat |= CONVERT;
                                activate(&bit_7);
                                }
                            else {
                                con->tstat &= (MASK - CONVERT);
                                activate(&bit_8);
                                }
                            }
                        }
                    else if (con->args[0] == 61) {
                        con->tstat |= CONVERT;
                        activate(&bit_7);
                        }
                    }
                break;
            case SEQ_DCS:
                if (c != ST) con->stat = SEQ_DCS;
                else if (c == ESC) con->stat = SEQ_ENDDCS;
                break;
            case SEQ_SPC:
                if (c == 'F') {
                    con->tstat |= CONVERT;
                    activate(&bit_7);
                    }
                else if (c == 'G') {
                    con->tstat &= (MASK - CONVERT);
                    activate(&bit_8);
                    }
                break;
            case SEQ_SEC:
                if (isdigit(c)) con->stat = SEQ_SEC;
                else if (c == 'c') sendstring(con,secda);
                break;
            case SEQ_RES:
                if (c == 'p') reset(con);
                break;
            case SEQ_G0:
                setset(con,cset(c),0);
                break;
            case SEQ_G1:
                setset(con,cset(c),1);
                break;
            case SEQ_G2:
                setset(con,cset(c),2);
                break;
            case SEQ_G3:
                setset(con,cset(c),3);
                break;
            case SEQ_ENDDCS:
                if (c != '/') con->stat = SEQ_DCS;
                break;
            default: ;
            }
        }
    else {
        cnt = 0;
        if (c & '\x80') {
            cnt = 4;
            if (con->tstat & DCONTHI) {
                if (con->ordc) textout(con);
                cnt |= 2;
                }
            if ((c >= '\xA0')&&(c < '\xFF')) {
                cnt |= 1;
                if (con->nstat & NATIONAL) c &= '\x7F';
                }
            }
        else {
            if (con->tstat & DCONTLO) {
                if (con->ordc) textout(con);
                cnt = 2;
                }
            if ((c >= ' ')&&(c < '\x7F')) cnt |= 1;
            }
        if (cnt & 3) {
            if (*(con->rows + con->row)) lim = COLUMNS / 2;
            else lim = COLUMNS;
            if (con->col > lim) {
                if (con->ordc) textout(con);
                if (con->tstat & WRAP) cursornextline(con);
                else con->col = lim;
                }
            if (con->ordc == 0) con->ordcol = con->col;
            con->ordtext[con->ordc] = c;
            con->ordc++;
            if (!(cnt & 2)) con->col++;
            if (con->tstat & GXGL) {
                setlset(con,con->slset);
                con->tstat &= (MASK - GXGL);
                }
            }
        if (!(cnt & 1)) {
            if (con->ordc) textout(con);
            if (cnt & 4) {
                switch (c) {
                    case CSI:
                        con->stat = SEQ_CSI;
                        con->argi = 0;
                        con->carg = 0;
                        break;
                    case IND:
                        cursordown(con,1);
                        break;
                    case NEL:
                        cursornextline(con);
                        break;
                    case HTS:
                        con->tabs[con->col] = 1;
                        break;
                    case RI:
                        cursorup(con,1);
                        break;
                    case SS2:
                        con->slset = con->lset;
                        con->tstat |= GXGL;
                        setlset(con,2);
                        break;
                    case SS3:
                        con->slset = con->lset;
                        con->tstat |= GXGL;
                        setlset(con,3);
                        break;
                    case DCS:
                        con->stat = SEQ_DCS;
                        break;
                    default: ;
                    }
                }
            else {
                switch (c) {
                    case ESC:
                        con->stat = SEQ_ESC;
                        break;
                    case BEL:
                        beep(con);
                        DisplayBeep(NULL);
                        break;
                    case BS:
                        if (con->col > 1) con->col--;
                        break;
                    case HT:
                        while (con->col < COLUMNS) {
                            con->col++;
                            if (con->tabs[con->col]) break;
                            }
                        break;
                    case VT:
                    case FF:
                    case LF:
                        if (con->tstat & NEWLINE) newline(con);
                        else cursordown(con,1);
                        break;
                    case CR:
                        con->col = 1;
                        break;
                    case SI:
                        setlset(con,0);
                        break;
                    case SO:
                        setlset(con,1);
                        break;
                    default: ;
                    }
                }
            }
        }
    }
return(0);
}

setset(struct console *con,USHORT set,USHORT seq)
{
con->mset[seq] = set;
switch(set) {
    case BRITISH:
        activate(&br_set);
        break;
    case DUTCH:
        activate(&du_set);
        break;
    case FINNISH:
        activate(&fi_set);
        break;
    case FRENCH:
        activate(&fr_set);
        break;
    case FRENCH_CANADIAN:
        activate(&fc_set);
        break;
    case GERMAN:
        activate(&ger_set);
        break;
    case ITALIAN:
        activate(&ita_set);
        break;
    case NORWEGIAN:
        activate(&nor_set);
        break;
    case SPANISH:
        activate(&spa_set);
        break;
    case SWEDISH:
        activate(&swe_set);
        break;
    case SWISS:
        activate(&swi_set);
        break;
    default:
    con->gset[seq] = set;
    }
if (con->lset == seq) setlset(con,seq);
if (con->rset == seq) setrset(con,seq);
return(0);
}
