/*
 * MAIN.C
 */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <typedefs.h>
#include "xmisc.h"
#include "defs.h"

#define KEY_LSHIFT   (1 << 0)
#define KEY_RSHIFT   (1 << 1)
#define KEY_CAPS     (1 << 2)
#define KEY_CTRL     (1 << 3)
#define KEY_ALTL     (1 << 4)
#define KEY_ALTR     (1 << 5)
#define KEY_AMIGAL   (1 << 6)
#define KEY_AMIGAR   (1 << 7)

#define QUAL_SHIFT   0x01
#define QUAL_CTRL    0x02
#define QUAL_AMIGA   0x04
#define QUAL_ALT     0x08


NW Nw = {
   0, 1, 640, 199, -1, -1,
   CLOSEWINDOW|NEWSIZE|RAWKEY|MOUSEBUTTONS|ACTIVEWINDOW,
   ACTIVATE|WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|RMBTRAP,
   NULL, NULL, "MED V1.01 (c)CopyRight 1986 Matthew Dillon,  All Rights Reserved                  ",
   NULL, NULL,
   32, 32, -1, -1,
   WBENCHSCREEN
};

WIN *Win;
RP  *Rp;

short Xsize, Ysize;           /* font character sizes                */
short Rows, Columns;          /* character rows/cols available       */
short Xbase, Ybase;           /* offset pixel base for display       */
short XTbase, YTbase;         /* used for text display               */
short Xpixs, Ypixs;           /* actual # X/Y pixels available       */

char *av[8];
char Quitflag;
char Overide;

extern ED E;
extern char memoryfail;

main(mac, mav)
char *mav[];
{
   IMESS *im;
   char notdone;
   char iawm;

   if (!openlibs(INTUITION_LIB|GRAPHICS_LIB))
      exiterr("cannot open intuition or graphics library");
   Win = OpenWindow(&Nw);
   if (Win == NULL)
      exiterr("cannot open window");
   Rp = Win->RPort;
   set_window_params();
   resethash();
   text_init();
   text_redisplay();

   if (mac == 2) {
      av[0] = "newfile";
      av[1] = mav[1];
      do_edit();
   }
   mountrequest(0);
   av[0] = NULL;
   av[1] = "c:.edrc";
   do_source();
   av[0] = NULL;
   av[1] = ".edrc";
   do_source();
   mountrequest(1);

   text_titleupdate();
loop:
    text_cursor(1);
   for (notdone = 1, iawm = 0; !Quitflag && notdone;) {
      window_title();
      WaitPort(Win->UserPort);
      while (im = (IMESS *)GetMsg(Win->UserPort)) {
         switch(im->Class) {
         case NEWSIZE:
            if (ComLineMode)
                escapecomlinemode();
            set_window_params();
            if (!text_sync())
               text_redisplay();
            text_cursor(1);
            break;
         case RAWKEY:
            text_cursor(0);
            keyctl(im->Code);
            text_cursor(1);
            break;
         case CLOSEWINDOW:
            if (ComLineMode)
                escapecomlinemode();
            notdone = 0;
            break;
         case ACTIVEWINDOW:
            iawm = 1;
            break;
         case MOUSEBUTTONS:
            if (iawm) {
                iawm = 0;
                break;
            }
            if (ComLineMode)
                escapecomlinemode();
            text_cursor(0);
            switch(im->Code) {
            case SELECTDOWN:        /* position cursor      */
                if (im->MouseY >= Ybase)
                    text_position((im->MouseX-Xbase)/Xsize,(im->MouseY-Ybase)/Ysize);
                else
                    text_position((im->MouseX-Xbase)/Xsize,-1);
                break;
            case MENUDOWN:          /* percentage placement */
                {
                    int line = 1 + (im->MouseY-(Ybase+4))*text_lines()/(Ypixs-8);
                    char buf[16];
                    if (line > text_lines())
                        line = text_lines();
                    if (line < 1)
                        line = 1;
                    sprintf(buf, "%ld", line);
                    av[1] = buf;
                    do_goto();
                }
                break;
            }
            text_cursor(1);
            break;
         }
         ReplyMsg(im);
      }
   }
   if (E.Modified && !Overide) {
      Overide = 1;
      SetWindowTitles(Win, "MED: File has been modified", NULL);
      Quitflag = 0;
      goto loop;
   }
   text_uninit();
   if (Win)
      CloseWindow(Win);
   closelibs(INTUITION_LIB|GRAPHICS_LIB);
   free_memory();
}

getyn(text)
char *text;
{
    int result;
    ITEXT *body, *pos, *neg;

    body = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    pos  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    neg  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    bzero(body, sizeof(ITEXT));
    bzero(pos , sizeof(ITEXT));
    bzero(neg , sizeof(ITEXT));
    body->BackPen = pos->BackPen = neg->BackPen = 1;
    body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;
    body->LeftEdge = 10;
    body->TopEdge  = 12;
    body->IText    = text;
    pos->LeftEdge = AUTOLEFTEDGE;
    pos->TopEdge = AUTOTOPEDGE;
    pos->IText = "OK";
    neg->LeftEdge = AUTOLEFTEDGE;
    neg->TopEdge = AUTOTOPEDGE;
    neg->IText = "CANCEL";
    result = AutoRequest(Win,body,pos,neg,0,0,320,58);
    FreeMem(body, sizeof(ITEXT));
    FreeMem(pos , sizeof(ITEXT));
    FreeMem(neg , sizeof(ITEXT));
    return(result);
}


char ShowTitle;

title(buf)
char *buf;
{
    SetWindowTitles(Win, buf, -1);
    ShowTitle = 1;
}


window_title()
{
   static char title[130];
   static char cmodified;
   int len;
   char *mod;

    if (memoryfail) {
        SetWindowTitles(Win, " -- NO MEMORY -- ", -1);
        text_redisplay();
        memoryfail = 0;
        return(0);
    }
    if (ShowTitle) {
        ShowTitle = 0;
        return(0);
    }
    if (text_titleupdate() || cmodified != E.Modified) {
        cmodified = E.Modified;
        mod = (E.Modified) ? " (modified)" : "";
        sprintf(title, "%3ld/%-3ld %s%s", text_lineno(), text_lines(), text_name(), mod);
        len = strlen(title);
        if (len < Columns && Columns < 128) {
            bset(title+len, Columns - len + 1, ' ');
            title[Columns + 1] = 0;
        }
        SetWindowTitles(Win, title, -1);
    }
}

inversemode(n)
{
   int v;

   v = JAM2;
   if (n)
      v = JAM2|INVERSVID;
   SetDrMd(Rp, v);
}

set_window_params()
{
   Xsize = Rp->Font->tf_XSize;
   Ysize = Rp->Font->tf_YSize;
   Xbase = Win->BorderLeft;
   Ybase = Win->BorderTop;
   Xpixs   = Win->Width - Win->BorderRight - Xbase;
   Ypixs   = Win->Height- Win->BorderBottom- Ybase;
   Columns = Xpixs / Xsize;
   Rows    = Ypixs / Ysize;
   XTbase   =  Xbase;
   YTbase   =  Ybase + Rp->Font->tf_Baseline;
}

exiterr(str)
char *str;
{
   puts(str);
   free_memory();
   exit(1);
}


#define HASHSIZE  64

typedef struct _HASH {
   struct _HASH *next;     /* next hash   */
   char code;              /* keycode     */
   char mask;              /* qual. mask  */
   char qual;              /* qual. comp  */
   char stat;              /* string static? */
   char *str;              /* command string */
} HASH;

HASH *Hash[HASHSIZE];

static char isalpha[] = {  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                           1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
                           1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
                           0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 };

static char ctoa[] = {
   '`','1','2','3','4','5','6','7','8','9','0','-','=','\\',0,'0',
   'q','w','e','r','t','y','u','i','o','p','[',']',0,'1','2','3',
   'a','s','d','f','g','h','j','k','l',';','\'',0,0,'4','5','6',
    0 ,'z','x','c','v','b','n','m',',','.','/',0,'.','7','8','9',
   ' ',0,0,0,0,0,0,0,0,0,'-',0,0,0,0,0
};

static char cstoa[]  = {
   '~','!','@','#','$','%','^','&','*','(',')','_','+','|',0,'0',
   'Q','W','E','R','T','Y','U','I','O','P','{','}',0,'1','2','3',
   'A','S','D','F','G','H','J','K','L',':','\"',0,0,'4','5','6',
    0 ,'Z','X','C','V','B','N','M','<','>','?',0,'.','7','8','9',
   ' ',0,0,0,0,0,0,0,0,0,'-',0,0,0,0,0
};

resethash()
{
    short i;
    register HASH *hash, *hnext = NULL;
    static struct {
        char *from, *to;
    } defmap[] = {
        "esc",      "esc",
        "return",   "return insline up firstnb down",
        "enter",    "return",
        "up",       "up",
        "down",     "down",
        "right",    "right",
        "left",     "left",
        "bs",       "bs",
        "del",      "del",
        "help",     "help",
        "tab",      "tab",
        "s-up",     "top",
        "s-down",   "bottom",
        "s-right",  "last",
        "s-left",   "first",
        "s-tab",    "backtab",
        "s-del",    "deline",
        "c-i",      "insertmode on",
        "c-o",      "insertmode off",
        "c-j",      "join",
        "c-s",      "split first down",
        "c-del",    "deline",
        "c-n",      "next",
        "c-p",      "prev",
        "c-/",      "escimm `find '",
        "c-up",     "pageup",
        "c-down",   "pagedown",
        "f1",       "escimm `insfile '",
        "f2",       "escimm `newfile '",
        "f9",       "escimm `bsave '",
        "f10",      "saveold quit",
        "c-b",      "block",
        "c-u",      "unblock",
        "a-d",      "bdelete",
        "a-c",      "bcopy",
        "a-m",      "bmove",
        NULL, NULL
    };

    for (i = 0; i < HASHSIZE; ++i) {
        for (hash = Hash[i]; hash; hash = hnext) {
            hnext = hash->next;
            if (!hash->stat)
                free(hash->str);
            free(hash);
        }
        Hash[i] = NULL;
    }
    for (i = 0; defmap[i].from; ++i) {
        char code, qual;
        if (get_codequal(defmap[i].from, &code, &qual))
            addhash(code, 1, -1, qual, defmap[i].to);
    }
}

returnoveride(n)
{
    HASH *hash;
    static char *str;
    static int stat;

    for (hash = Hash[0x44 % HASHSIZE]; hash; hash = hash->next) {
        if (hash->code == 0x44 && hash->qual == 0) {
            if (n) {
                str = hash->str;
                stat= hash->stat;
                hash->str = "return";
                hash->stat = 1;
            } else {
                if (str == NULL) {
                    remhash(0x44, -1, 0);
                } else {
                    hash->str = str;
                    hash->stat= stat;
                }
            }
            return(0);
        }
    }
    if (n) {
        addhash(0x44,1,-1,0,"return");
        str = NULL;
    }
}



addhash(code, stat, mask, qual, str)
char *str;
{
   register HASH **p, *hash;

   hash = *(p = &Hash[code % HASHSIZE]);
   while (hash) {
      if (hash->code == code && hash->qual == qual && hash->mask == mask) {
         if (!hash->stat)
            free(hash->str);
         goto newstr;
      }
      hash = *(p = &hash->next);
   }
   *p = hash = (HASH *)malloc(sizeof(HASH));
   hash->next = NULL;
newstr:
   hash->code = code;
   hash->stat = stat;
   hash->mask = mask;
   hash->qual = qual;
   hash->str = str;
   if (!stat)           /* if not static */
      hash->str = (char *)strcpy(malloc(strlen(str)+1), str);
}


remhash(code, mask, qual)
{
   HASH *hash, **p;

   hash = *(p = &Hash[code % HASHSIZE]);
   while (hash) {
      if (hash->code == code && hash->qual == qual && hash->mask == mask) {
         if (!hash->stat)
            free(hash->str);
         *p = hash->next;
         free(hash);
         return(1);
      }
      hash = *(p = &hash->next);
   }
   return(0);
}


keyctl(code)
char code;
{
   static char state;
   register char c, c2;
   register HASH *hash;

   if ((code & 0x78) == 0x60) {
      c2 = 1 << (code & 7);
      if (code & 0x80)
         state &= ~c2;
      else
         state |= c2;
      return(0);
   }
   if (code & 0x80)
      return(0);
   c2 = 0;
   if (state & (KEY_LSHIFT|KEY_RSHIFT))   c2 |= QUAL_SHIFT;
   if (state & (KEY_CTRL             ))   c2 |= QUAL_CTRL;
   if (state & (KEY_AMIGAL|KEY_AMIGAR))   c2 |= QUAL_AMIGA;
   if (state & (KEY_ALTL  |KEY_ALTR  ))   c2 |= QUAL_ALT;
   if ((state & KEY_CAPS) && (code <= 0x37) && (isalpha[code]))
         c2 |= QUAL_SHIFT;
   for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) {
      if (hash->code == code) {
         if ((c2 & hash->mask) == hash->qual)
            break;
      }
   }
   if (hash) {
      char buf[256];
      strcpy(buf, hash->str);
      do_command(buf);
   } else {
      /* disallow CTL, ALT, and non-ascii keys. form: 'c or "ccc.."  */
      if (code < 0x50) {
         c = (c2 & QUAL_SHIFT) ? cstoa[code] : ctoa[code];
         if (c) {
            char buf[3];
            buf[0] = '\'';
            buf[1] = c;
            buf[2] = 0;
            do_command(buf);
         }
      }
   }
}

#define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)

long lname[] = {
   LN('e','s','c',0x45), LN('f','1', 0 ,0x50), LN('f','2', 0 ,0x51),
   LN('f','3', 0 ,0x52), LN('f','4', 0 ,0x53), LN('f','5', 0 ,0x54),
   LN('f','6', 0 ,0x55), LN('f','7', 0 ,0x56), LN('f','8', 0 ,0x57),
   LN('f','9', 0 ,0x58), LN('f','1','0',0x59), LN('d','e','l',0x46),
   LN('b','a','c',0x41), LN('b','s', 0 ,0x41), LN('t','a','b',0x42),
   LN('h','e','l',0x5F), LN('r','e','t',0x44), LN('u','p', 0 ,0x4C),
   LN('d','o','w',0x4D), LN('r','i','g',0x4E), LN('l','e','f',0x4F),
   LN('e','n','t',0x43), LN('n','k','-',0x4A), LN('n','k','.',0x3C),
   LN('n','k','0',0x0F),
   LN('n','k','1',0x1D), LN('n','k','2',0x1E), LN('n','k','3',0x1F),
   LN('n','k','4',0x2D), LN('n','k','5',0x2E), LN('n','k','6',0x2F),
   LN('n','k','7',0x3D), LN('n','k','8',0x3E), LN('n','k','9',0x3F),
   0
};


get_codequal(str, pcode, pqual)
char *pcode, *pqual;
char *str;
{
   char qual;
   register short i;

   qual = 0;
   if (strlen(str) > 1) {
      for (; *str && *str != '-'; ++str) {
         if (*str == 's')
            qual |= QUAL_SHIFT;
         if (*str == 'c')
            qual |= QUAL_CTRL;
         if (*str == 'a')
            qual |= QUAL_ALT;
         if (!qual)
            goto notqual;
      }
      if (*str)
         ++str;
   }
notqual:
   *pqual = qual;
   if (strlen(str) != 1) {           /* long name   */
      register short shift = 24;
      register long mult = 0;

      while (*str && shift >= 8) {
         if (*str >= 'A' && *str <= 'Z')
            *str = *str - 'A' + 'a';
         mult |= *str << shift;
         shift -= 8;
         ++str;
      }
      for (i = 0; lname[i]; ++i) {
         if (mult == (lname[i] & 0xFFFFFF00)) {
            *pcode = lname[i] & 0x7F;
            return(1);
         }
      }
   } else {                         /* short name  */
      for (i = 0; i < sizeof(ctoa); ++i) {
         if (*str == ctoa[i]) {
            *pcode = i;
            return(1);
         }
      }
      for (i = 0; i < sizeof(cstoa); ++i) {
         if (*str == cstoa[i]) {
            *pcode = i;
            *pqual |= QUAL_SHIFT;
            return(1);
         }
      }
   }
   return(0);
}

do_map()
{
    char code, qual;

    if (get_codequal(av[1], &code, &qual)) {
        addhash(code, 0, -1, qual, av[2]);
    } else {
        title("Unknown Command");
    }
}

do_unmap()        /* key   */
{
   char code, qual;

   if (get_codequal(av[1], &code, &qual)) {
      remhash(code, -1, qual);
   } else {
        title("Unknown Command");
   }
}

do_clearmap()
{
   resethash();
}
