/*************************************************************************
 ***                            suppcom.c                (JJB TEMPLAR) ***
 *** Date begun: 11/8/89 - copied from hardcopy of old prim.c          ***
 *** Last modified: 27/8/89.                                           ***
 *************************************************************************/
/*** The pattern matching algorithm used is the Knuth-Morris-Pratt one ***
 *** as detailed in:-                                                  ***
 ***    "Computer Algorithms: Introduction to Design and Analysis"     ***
 ***            by Sara Baase.                                         ***
 *************************************************************************/

#include "less.h"
#include "position.h"
#include "screen.h"

#include <intuition/intuition.h>
#include "iconify.h"

extern struct Window    *Window;
extern struct NewWindow NewWindow;
extern UWORD far    image10[420];
extern int          fast_line,twiddle,back_scroll,top_scroll,quit_at_eof,
                    squeeze,scroll_bar;
extern int          has_resized;
extern BPTR         file;

extern char *line;

char    *modedata[] = {
"\n    [32mTy 1.3 User Changeable Modes:[m\n\n",
"    (0) Cancel ........ don't change any modes.\n\n",
"    (1) Fast line ..... check for ~` or control characters.\n",
"    (2) Twiddle ....... output a ~ for lines beyond EOF.\n",
"    (3) Back scroll ... allow backwards scrolling.\n",
"    (4) Top scroll .... draw from top of screen.\n",
"    (5) Quit at EOF ... quit after two attempts to pass EOF.\n",
"    (6) Squeeze ....... squeeze multiple blank lines together.\n",
"    (7) Scroll bar .... activate vertical scroll bar.\n\n\n\n\n\n\n\n",
"    [3mSorry about the cruddy numbered menu system, but this'll be made a\n",
"    requester... eventually.[m\n",
"                                [33m(SELECT NUMBER)[m",
NULL};
static LONG marks[10];  /* The table of marks. */

struct Image    iconimg = {0,0,70,42,2,image10,3,0,NULL};

#define PATLEN   20
char    pat[PATLEN + 3];    /* Two characters extra */
char    tup[PATLEN + 3];    /* Copy of pat, but all upper case */
int     flink[PATLEN + 3];
int     pat_opt;            /* Should be set by option reader whenever a
                             * new pattern is specified. */

int     toupp(ch) /*=====================================================*/
register int    ch;
{
    if ((ch >= 'a') && (ch <= 'z')) ch += 'A' - 'a';
    return(ch);
}

static void doflink() /*=================================================*/
{                     /* Set up flink[], using pat[] as pattern.         */
register int    i,j;
register char   *cp = pat,*tp = tup;
    while (*cp) *tp++ = toupp(*cp++);
    *tp = 0;                        /* Terminate string! */
    flink[0] = -1;   i = 1;
    while (tup[i]) {
        j = flink[i-1];
        while ((j != -1) && (tup[j] != tup[i-1]) && (tup[j] != '?')) j = flink[j];
        flink[i] = j + 1;
        i++;
    }
    pat_opt = 0;    /* Turn off pattern option flag */
}

static int  match(buf) /*================================================*/
register char *buf;
{
register char   *p = tup;
register int    j;
    j = 0;
    while (*buf) {
        while ((j != -1) && (p[j] != toupp(*buf)) && (p[j] != '?')) j = flink[j];
        if (!p[j+1]) return(1);
        else {  buf++;  j++; }
    }
    return(0);
}

void    search_forw(f) /*================================================*/
int     f;
{
LONG    pos,lpos;
    if ((f || !pat[0]) &&
        (!(f = r_string("Forward Search",pat,PATLEN+1)) || !pat[0])) return;

    if (position(TOP) == NULL_POSITION) pos = 0;
    else pos = position(TOP_PLUS_ONE);

    if (pos == NULL_POSITION) {
        error("Nothing to search!",0);
        return;
    }

    if (f || pat_opt) doflink();
    while (1) {
        lpos = pos;
        pos = forw_raw_line(pos);

        if (pos == NULL_POSITION) {
            error("Pattern not found",0);
            return;
        }

        if (match(line)) break;
    }

    jump_loc(lpos);
}

void    search_back(f) /*================================================*/
int     f;
{
LONG    pos,lpos;
    if ((f || !pat[0]) &&
        (!(f = r_string("Backward Search",pat,PATLEN+1)) || !pat[0])) return;
        /* The above sets f to 1 if user entered pattern, if f was zero */

    if (position(TOP) == NULL_POSITION) pos = 0;
    else pos = position(TOP);

    if (pos == NULL_POSITION) {
        error("Nothing to search!",0);
        return;
    }

    if (f || pat_opt) doflink();
    while (1) {
        pos = back_raw_line(pos);
        lpos = pos;

        if (pos == NULL_POSITION) {
            error("Pattern not found",0);
            return;
        }

        if (match(line)) break;
    }

    jump_loc(lpos);
}

void    doiconify() /*===================================================*/
{
static int      success = 1;
static UWORD    x,y;        /* Initialised to zero */
register int    temp;

    if (success) {
        NewWindow.LeftEdge = Window->LeftEdge;  /* Save window dimensions */
        NewWindow.TopEdge = Window->TopEdge;
        NewWindow.Height = Window->Height;
        NewWindow.Width = Window->Width;
        NewWindow.Title = Window->Title;

        ttclose();                          /* Close Window and console */

        success = iconify(&x,&y,iconimg.Width,iconimg.Height,NULL,(APTR)&iconimg,ICON_IMAGE);

        ttopen();                        /* Get back window and console */
        temp = top_scroll;  top_scroll = 1;
        repaint();
        top_scroll = temp;
        if (!success) error("Iconify failed!",0);
    }
    else {
        error("Iconify disabled.",0);
    }
}

void    print() /*=======================================================*/
{
UBYTE   buf[512];       /* Buffer on the fly, as it were... */
register ULONG  oldpos; /* Seek back to initial file pos?   */
register BPTR   prt;
register int    size;
    if (!file || !r_bool("Really print file?")) return;
    if (!(prt = Open("PRT:",MODE_NEWFILE))) {
        error("Failed to open printer!",0);
        return;
    }
    oldpos = Seek(file,0,OFFSET_BEGINNING);
    while ((size = Read(file,buf,512)) > 0) {
        if (Write(prt,buf,size) != size) {
            error("Printing error!",0);
            break;
        }
    }
    Close(prt);
    Seek(file,oldpos,OFFSET_BEGINNING);
}

void    init_mark() /*===================================================*/
{                   /* Clear all marks.                                  */
register int    i;
    for (i = 0;  i < 10;  i++) marks[i] = NULL_POSITION;
}

static int  badmark(c) /*================================================*/
register int    c;     /* See if c is a valid mark char (a - z).         */
{
    if ((c < 0x01) || (c > 0x0a)) {     /* RAWKEY */
        error("Must be a digit in [0,9]!",0);
        return(1);
    }
    return(0);
}

static int  getmark(cp) /*===============================================*/
register char   *cp;
{
register int    c;
    SetWindowTitles(Window,cp,(char *)-1L);
    c = getc();
    return((badmark(c))? -1: c - 1);   /* mark '0' actually pos 9 in table,
                 * since RAWKEY goes 1,2,...,9,0 instead of 0,1,...,8,9. */
}

void    setmark() /*=====================================================*/
{
register int    c;
    if ((c = getmark("Mark: set mark [0-9] ")) >= 0)
        marks[c] = position(TOP);
}

void    gomark() /*======================================================*/
{
register int    c;
    if ((c = getmark("Mark: go to mark [0-9] ")) < 0)
        return;    /* Failed */
    if (marks[c] == NULL_POSITION) error("Mark not set",0);
    else jump_loc(marks[c]);
}

void    domode(on) /*====================================================*/
register int    on;
{
register char   **ch = modedata;

    SetWindowTitles(Window,(on)?"Mode ON":"Mode OFF",(char *)-1L);
    clear();
    while (*ch) puts(*ch++);
    flush();

    switch (getc()) {
        case (0x01): fast_line = on;        break;
        case (0x02): twiddle = on;          break;
        case (0x03): back_scroll = on * 30; break;
        case (0x04): top_scroll = on;       break;
        case (0x05): quit_at_eof = on;      break;
        case (0x06): squeeze = on;          break;
        case (0x07): scroll_bar = on;
                     setbar(2);
                     break;
    }
    if (has_resized) {
        resize();
        has_resized = 0;
    }
}
