#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include "flayer.h"
#include "samterm.h"

uchar   **name; /* first byte is ' ' or '\'': modified state */
Text    **text; /* pointer to Text associated with file */
ushort  *tag;           /* text[i].tag, even if text[i] not defined */
int     nname;
int     mname;
int     mw;

char    *genmenu3(int);
char    *genmenu2(int);
char    *genmenu2c(int);

enum Menu2
{
       Cut,
       Paste,
       Snarf,
       Plumb,
       Look,
       Exch,
       Search,
       NMENU2 = Search,
       Send = Search,
       NMENU2C
};

enum Menu3
{
       New,
       Zerox,
       Resize,
       Close,
       Write,
       NMENU3
};

char    *menu2str[] = {
       "cut",
       "paste",
       "snarf",
       "plumb",
       "look",
       "<rio>",
       0,              /* storage for last pattern */
};

char    *menu3str[] = {
       "new",
       "zerox",
       "resize",
       "close",
       "write",
};

Menu    menu2 = {0, genmenu2};
Menu    menu2c ={0, genmenu2c};
Menu    menu3 = {0, genmenu3};

void
menu2hit(void)
{
       Text *t=(Text *)which->user1;
       int w = which-t->l;
       int m;

       if(hversion==0 || plumbfd<0)
               menu2str[Plumb] = "(plumb)";
       m = menuhit(2, mousectl, t==&cmd? &menu2c : &menu2, nil);
       if(hostlock || t->lock)
               return;

       switch(m){
       case Cut:
               cut(t, w, 1, 1);
               break;

       case Paste:
               paste(t, w);
               break;

       case Snarf:
               snarf(t, w);
               break;

       case Plumb:
               if(hversion > 0)
                       outTsll(Tplumb, t->tag, which->p0, which->p1);
               break;

       case Exch:
               snarf(t, w);
               outT0(Tstartsnarf);
               setlock();
               break;

       case Look:
               outTsll(Tlook, t->tag, which->p0, which->p1);
               setlock();
               break;

       case Search:
               outcmd();
               if(t==&cmd)
                       outTsll(Tsend, 0 /*ignored*/, which->p0, which->p1);
               else
                       outT0(Tsearch);
               setlock();
               break;
       }
}

void
menu3hit(void)
{
       Rectangle r;
       Flayer *l;
       int m, i;
       Text *t;

       mw = -1;
       switch(m = menuhit(3, mousectl, &menu3, nil)){
       case -1:
               break;

       case New:
               if(!hostlock)
                       sweeptext(1, 0);
               break;

       case Zerox:
       case Resize:
               if(!hostlock){
                       setcursor(mousectl, &bullseye);
                       buttons(Down);
                       if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && getr(&r))
                               duplicate(l, r, l->f.font, m==Resize);
                       else
                               setcursor(mousectl, cursor);
                       buttons(Up);
               }
               break;

       case Close:
               if(!hostlock){
                       setcursor(mousectl, &bullseye);
                       buttons(Down);
                       if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && !hostlock){
                               t=(Text *)l->user1;
                               if (t->nwin>1)
                                       closeup(l);
                               else if(t!=&cmd) {
                                       outTs(Tclose, t->tag);
                                       setlock();
                               }
                       }
                       setcursor(mousectl, cursor);
                       buttons(Up);
               }
               break;

       case Write:
               if(!hostlock){
                       setcursor(mousectl, &bullseye);
                       buttons(Down);
                       if((mousep->buttons&4) && (l = flwhich(mousep->xy))){
                               outTs(Twrite, ((Text *)l->user1)->tag);
                               setlock();
                       }else
                               setcursor(mousectl, cursor);
                       buttons(Up);
               }
               break;

       default:
               if(t = text[m-NMENU3]){
                       i = t->front;
                       if(t->nwin==0 || t->l[i].textfn==0)
                               return; /* not ready yet; try again later */
                       if(t->nwin>1 && which==&t->l[i])
                               do
                                       if(++i==NL)
                                               i = 0;
                               while(i!=t->front && t->l[i].textfn==0);
                       current(&t->l[i]);
               }else if(!hostlock)
                       sweeptext(0, tag[m-NMENU3]);
               break;
       }
}


Text *
sweeptext(int new, int tag)
{
       Rectangle r;
       Text *t;

       if(getr(&r) && (t = malloc(sizeof(Text)))){
               memset((void*)t, 0, sizeof(Text));
               current((Flayer *)0);
               flnew(&t->l[0], gettext, 0, (char *)t);
               flinit(&t->l[0], r, font, maincols);    /*bnl*/
               t->nwin = 1;
               rinit(&t->rasp);
               if(new)
                       startnewfile(Tstartnewfile, t);
               else{
                       rinit(&t->rasp);
                       t->tag = tag;
                       startfile(t);
               }
               return t;
       }
       return 0;
}

int
whichmenu(int tg)
{
       int i;

       for(i=0; i<nname; i++)
               if(tag[i] == tg)
                       return i;
       return -1;
}

void
menuins(int n, uchar *s, Text *t, int m, int tg)
{
       int i;

       if(nname == mname){
               if(mname == 0)
                       mname = 32;
               else
                       mname *= 2;
               name = realloc(name, sizeof(name[0])*mname);
               text = realloc(text, sizeof(text[0])*mname);
               tag = realloc(tag, sizeof(tag[0])*mname);
               if(name==nil || text==nil || tag==nil)
                       panic("realloc");
       }
       for(i=nname; i>n; --i)
               name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1];
       text[n] = t;
       tag[n] = tg;
       name[n] = alloc(strlen((char*)s)+2);
       name[n][0] = m;
       strcpy((char*)name[n]+1, (char*)s);
       nname++;
       menu3.lasthit = n+NMENU3;
}

void
menudel(int n)
{
       int i;

       if(nname==0 || n>=nname || text[n])
               panic("menudel");
       free(name[n]);
       --nname;
       for(i = n; i<nname; i++)
               name[i]=name[i+1], text[i]=text[i+1], tag[i]=tag[i+1];
}

void
setpat(char *s)
{
       static char pat[17];

       pat[0] = '/';
       strncpy(pat+1, s, 15);
       menu2str[Search] = pat;
}

#define NBUF    64
static uchar buf[NBUF*UTFmax]={' ', ' ', ' ', ' '};

char *
paren(char *s)
{
       uchar *t = buf;

       *t++ = '(';
       do; while(*t++ = *s++);
       t[-1] = ')';
       *t = 0;
       return (char *)buf;
}
char*
genmenu2(int n)
{
       Text *t=(Text *)which->user1;
       char *p;
       if(n>=NMENU2+(menu2str[Search]!=0))
               return 0;
       p = menu2str[n];
       if(!hostlock && !t->lock || n==Search || n==Look)
               return p;
       return paren(p);
}
char*
genmenu2c(int n)
{
       Text *t=(Text *)which->user1;
       char *p;
       if(n >= NMENU2C)
               return 0;
       if(n == Send)
               p="send";
       else
               p = menu2str[n];
       if(!hostlock && !t->lock)
               return p;
       return paren(p);
}
char *
genmenu3(int n)
{
       Text *t;
       int c, i, k, l, w;
       Rune r;
       char *p;

       if(n >= NMENU3+nname)
               return 0;
       if(n < NMENU3){
               p = menu3str[n];
               if(hostlock)
                       p = paren(p);
               return p;
       }
       n -= NMENU3;
       if(n == 0)      /* unless we've been fooled, this is cmd */
               return (char *)&name[n][1];
       if(mw == -1){
               mw = 7; /* strlen("~~sam~~"); */
               for(i=1; i<nname; i++){
                       w = utflen((char*)name[i]+1)+4; /* include "'+. " */
                       if(w > mw)
                               mw = w;
               }
       }
       if(mw > NBUF)
               mw = NBUF;
       t = text[n];
       buf[0] = name[n][0];
       buf[1] = '-';
       buf[2] = ' ';
       buf[3] = ' ';
       if(t){
               if(t->nwin == 1)
                       buf[1] = '+';
               else if(t->nwin > 1)
                       buf[1] = '*';
               if(work && t==(Text *)work->user1) {
                       buf[2]= '.';
                       if(modified)
                               buf[0] = '\'';
               }
       }
       l = utflen((char*)name[n]+1);
       if(l > NBUF-4-2){
               i = 4;
               k = 1;
               while(i < NBUF/2){
                       k += chartorune(&r, (char*)name[n]+k);
                       i++;
               }
               c = name[n][k];
               name[n][k] = 0;
               strcpy((char*)buf+4, (char*)name[n]+1);
               name[n][k] = c;
               strcat((char*)buf, "...");
               while((l-i) >= NBUF/2-4){
                       k += chartorune(&r, (char*)name[n]+k);
                       i++;
               }
               strcat((char*)buf, (char*)name[n]+k);
       }else
               strcpy((char*)buf+4, (char*)name[n]+1);
       i = utflen((char*)buf);
       k = strlen((char*)buf);
       while(i<mw && k<sizeof buf-1){
               buf[k++] = ' ';
               i++;
       }
       buf[k] = 0;
       return (char *)buf;
}