/* SSS IconBar handler
   Tue,30 Jul 1991
   Copyright C.T.Stretch 1991
*/

#include "ssshdr.h"
#include "drhdr.h"
#include "akbd.h"

#define HOMEKEY 30
#define PROGNAME "SSS"
#define NONULL wimp_EMNULL
#define PRWIDTH 2
#define PRSEP 4
#define PRREP 6
#define PRMONO 9
#define PRA4P 11
#define PRREAD 14

static wimp_w bwind;
static menu barmenu,wmenu;
static dbox edbox;
static int dx=0,dy=1;

static void setext()
{ int i,w=0;
  wimp_redrawstr r;
  wimp_wstate ws;
  wimp_close_wind(swind);
  r.w=swind;
  r.box.x0=0;
  for(i=0;i<ncols;i++) w+=width[i];
  dispwidth=w*CHWIDTH;
  r.box.x1=dispwidth;
  r.box.y1=0;
  r.box.y0=-LINEHT*nrows;
  wimpt_noerr(wimp_set_extent(&r));
  wimp_get_wind_state(swind,&ws);
  wimpt_noerr(wimp_open_wind(&(ws.o)));
}

static void fred()
{ wimp_wstate ws;
  wimp_get_wind_state(swind,&ws);
  ws.o.box.x0=0;
  ws.o.box.y1=0;
  ws.o.box.x1=dispwidth;
  ws.o.box.y0=-LINEHT*nrows;
  wimp_force_redraw((wimp_redrawstr*)&(ws.o));
}

static void showentry()
{ entry **cb=sheet+sx0+sy0*NCOLS;
  char tstr[64];
  int t;
  wimp_caretstr cs;
  for(t=ICSTRING;t<ICRIGHT;t++) dbox_setnumeric(edbox,t,0);
  if(*cb)
  { t=(*cb)->t;
    dbox_setnumeric(edbox,ICSTRING+t,1);
    dbox_setfield(edbox,ICWRITE,&((*cb)->c));
  }
  else
  { t=FINT;
    if(sy0>0)
    { cb=sheet+sx0+(sy0-1)*NCOLS;
      if(*cb) t=(*cb)->t;
    }
    dbox_setnumeric(edbox,ICSTRING+t,1);
    dbox_setfield(edbox,ICWRITE,"");
  }
  ex0=sx0;ex1=sx1;ey0=sy0;ey1=sy1;
  if(sx0==sx1&&sy0==sy1) sprintf(tstr,"Edit [%d,%d]",sx0,sy0);
  else sprintf(tstr,"Edit [%d,%d][%d,%d]",sx0,sy0,sx1,sy1);
  sheet_ebox();
  win_settitle(bwind,tstr);
  dbox_showstatic(edbox);
  cs.w=bwind;
  cs.i=ICWRITE;
  cs.x=-1;cs.y=-1;
  cs.height=-1;
  cs.index=0;
  wimpt_noerr(wimp_set_caret_pos(&cs));
}

static void showprev()
{ entry **cb=sheet+sx0+sy0*NCOLS;
  int t;
  for(t=ICSTRING;t<ICRIGHT;t++) dbox_setnumeric(edbox,t,0);
  if(*cb)
  { t=(*cb)->t;
    dbox_setnumeric(edbox,ICSTRING+t,1);
    dbox_setfield(edbox,ICWRITE,&((*cb)->c));
  }
  else
  { dbox_setnumeric(edbox,ICSTRING+FINT,1);
    dbox_setfield(edbox,ICWRITE,"");
  }
  sx0=ex0;sx1=ex1;sy0=ey0;sy1=ey1;
  sheet_box();
}

static void mouse(wimp_mousestr *m)
{ int bx,by,x;
  wimp_wstate state;
  wimpt_noerr(wimp_get_wind_state(swind,&state));
  bx=state.o.box.x0-state.o.x;
  by=state.o.box.y1-state.o.y;
  switch(m->bbits)
  { case wimp_BLEFT:x=(m->x-bx+8)/CHWIDTH;
                    for(sx0=0;((x-=width[sx0])>0)&&(sx0<ncols-1);sx0++);
                    sy0=(by-m->y)/LINEHT;
                    if(sy0>=nrows) sy0=nrows-1;
                    sx1=sx0;sy1=sy0;
                    sheet_box();
                    break;
    case wimp_BRIGHT:x=(m->x-bx+8)/CHWIDTH;
                    for(sx1=0;((x-=width[sx1])>0)&&(sx1<ncols-1);sx1++);
                    sy1=(by-m->y)/LINEHT;
                    if(sy1>=nrows)sy1=nrows-1;
                    if(sx0>sx1) {x=sx0;sx0=sx1;sx1=x;}
                    if(sy0>sy1) {x=sy0;sy0=sy1;sy1=x;}
                    sheet_box();
                    break;
  }
}

static void openedit()
{ dbox_hide(edbox);
  showentry();
}

static void barclick(wimp_i i)
{ wimp_wstate ws;
  i=i;
  setext();
  wimp_get_wind_state(swind,&ws);
  ws.o.behind=-1;
  wimpt_noerr(wimp_open_wind(&(ws.o)));
  openedit();
}

static void display(wimp_redrawstr *r)
{ int bx,by,more,tl,bl,l,i,x1,x2;
  entry *ce;
  char num[256];
  wimpt_noerr(wimp_redraw_wind(r,&more));
  bx=r->box.x0-r->scx;
  by=r->box.y1-r->scy;
  while(more)
  { wimp_setcolour(7);
    tl=(by-r->g.y1)/LINEHT;
    if(tl<0) tl=0;
    bl=(by-r->g.y0)/LINEHT;
    if(bl>=nrows) bl=nrows-1;
    for(l=tl;l<=bl;l++)
    { bbc_move(r->g.x0,by-LINEHT*l);
      bbc_draw(r->g.x1,by-LINEHT*l);
    }
    x1=bx;
    for(i=0;i<ncols;i++) if(width[i])
    { x2=x1+width[i]*CHWIDTH;
      if(x1>r->g.x1) break;
      if(x2>=r->g.x0)
      { bbc_move(x2,r->g.y0);
        bbc_draw(x2,r->g.y1);
      }
      if(x2>r->g.x0) for(l=tl;l<=bl;l++)
      { ce=sheet[i+l*NCOLS];
        if(ce)
        { bbc_move(x1+XOFF,by-LINEHT*l-YOFF);
          if(ce->p) printf("%.*s",width[i]-1,"P???????");
          else
          { if(ce->a) printf("%.*s",width[i]-1,"A!!!!!!!");
            else switch(ce->t)
            { case FSTRING:
              case FLONG:printf("%.*s",width[i]-1,&(ce->c));break;
              case FINT:sprintf(num,"%.0f",ce->v);
                        printf("%.*s",width[i]-1,num);break;
              case F2DP:sprintf(num,"%.2f",ce->v);
                        printf("%.*s",width[i]-1,num);break;
              case F4DP:sprintf(num,"%.4f",ce->v);
                        printf("%.*s",width[i]-1,num);break;
              case FEXP:sprintf(num,"%.4e",ce->v);
                        printf("%.*s",width[i]-1,num);break;
            }
          }
        }
      }
      x1=x2;
    }
    wimp_setcolour(15+16*3);
    bbc_rectanglefill(bx+bx0,by-by1,bw,bh);
    bbc_rectanglefill(bx+bx0+8,by-by1+8,bw-16,bh-16);
    wimp_setcolour(12+16*3);
    bbc_rectanglefill(bx+ebx0,by-eby1,ebw,ebh);
    wimp_get_rectangle(r,&more);
  }
}

static void update()
{ if(uy>=nrows)
  { uy=0;
    if(changed) fred();
    if(!autox||!changed)
    { event_setmask(NONULL);
      return;
    }
    changed=FALSE;
  }
  sheet_update();
  uy++;
}

static void handler(wimp_eventstr *e,void *v)
{ v=v;
  switch(e->e)
  { case wimp_ENULL  :update();break;
    case wimp_EREDRAW:display((wimp_redrawstr*)(&(e->data.o)));break;
    case wimp_EOPEN  :wimpt_noerr(wimp_open_wind(&(e->data.o)));break;
    case wimp_ECLOSE :wimpt_noerr(wimp_close_wind(e->data.o.w));break;
    case wimp_EBUT   :mouse(&(e->data.but.m));break;
    case wimp_ESEND:case wimp_ESENDWANTACK:
              switch (e->data.msg.hdr.action)
              { case wimp_MDATALOAD:io_merge();setext();break;
              }
              break;
  }
}

static void getdirn()
{ if(dbox_getnumeric(edbox,ICRIGHT))
  { dx=1;dy=0;return;
  }
  dx=0;dy=1;
}

static void getnext()
{ getdirn();
  if(ex0==ex1)
  { sx0=ex0+dx;
    if(sx0>=ncols) sx0=ncols-1;
    sx1=sx0;
  }
  else
  { sx0=ex0;sx1=ex1;
  }
  if(ey0==ey1)
  { sy0=ey0+dy;
    if(sy0>=nrows) sy0=nrows-1;
    sy1=sy0;
  }
  else
  { sy0=ey0;sy1=ey1;
  }
  sheet_box();
  showentry();
}

static void insrange(BOOL rel)
{ wimp_caretstr cs;
  int n;
  char buf2[BUFLEN];
  wimp_get_caret_pos(&cs);
  if(cs.w!=bwind) werr(0,"window %d",cs.w);
  n=cs.index;
  dbox_getfield(edbox,ICWRITE,buf,BUFLEN);
  if(strlen(buf)+27>=BUFLEN) return;
  if(sx0==sx1&&sy0==sy1)
  { if(rel) sprintf(buf2,"%.*s[x%+d,y%+d]%s",n,buf,sx0-ex0,sy0-ey0,buf+n);
    else
        sprintf(buf2,"%.*s[%d,%d]%s",n,buf,sx0,sy0,buf+n);
  }
  else
  { if(rel)
    { sprintf(buf2,"%.*s[x%+d,y%+d][x%+d,y%+d]%s",
            n,buf,sx0-ex0,sy0-ey0,sx1-ex0,sy1-ey0,buf+n);
    }
    else
        sprintf(buf2,"%.*s[%d,%d][%d,%d]%s",
        n,buf,sx0,sy0,sx1,sy1,buf+n);
  }
  dbox_setfield(edbox,ICWRITE,buf2);
  cs.index+=strlen(buf2)-strlen(buf);
  wimpt_noerr(wimp_set_caret_pos(&cs));
}

static void edhandler(dbox d,void *h)
{ dbox_field f=dbox_get(d);
  int x,y,t;
  entry *cb;
  h=h;
  switch (f)
  { case dbox_CLOSE:dbox_hide(d);break;
    case ICOK:dbox_getfield(d,ICWRITE,buf,256);
           for(t=0;t<FEXP;t++) if(dbox_getnumeric(edbox,ICSTRING+t)) break;
           for(x=ex0;x<=ex1;x++) if(width[x])
             for(y=ey0;y<=ey1;y++) sheet_getentry(x,y,t);
           fred();
           getnext();
           if(autox) sheet_change();
           break;
    case ICEDIT:showentry();break;
    case ICFORMAT:
           for(t=0;t<FEXP;t++) if(dbox_getnumeric(edbox,ICSTRING+t)) break;
           if(t<FINT) break;
           for(x=ex0;x<=ex1;x++) for(y=ey0;y<=ey1;y++)
           { cb=sheet[x+y*NCOLS];
             if(cb&&cb->t>=FINT) cb->t=t;
           }
           fred();break;
    case ICNEXT:getnext();break;
    case ICCANCEL:showprev();break;
    case ICABS:insrange(0);break;
    case ICREL:insrange(1);break;
    default:break;
  }
}

static BOOL edkeys(dbox d,void *e,void *h)
{ wimp_wstate state;
  h=h;d=d;
  if(((wimp_eventstr*)e)->e!=wimp_EKEY) return FALSE;
  switch(((wimp_eventstr*)e)->data.key.chcode)
  { case HOMEKEY:if(akbd_pollsh())
                 { sx0=sx1=ncols-1;sy0=sy1=nrows-1;
                   wimp_get_wind_state(swind,&state);
                   state.o.x=dispwidth-state.o.box.x0+state.o.box.x1;
                   state.o.y=-nrows*LINEHT-state.o.box.y0+state.o.box.y1;
                 }
                 else
                 { sx0=0;sx1=0;sy0=0;sy1=0;
                   wimp_get_wind_state(swind,&state);
                   state.o.x=0;
                   state.o.y=0;
                 }
                   wimp_open_wind(&(state.o));
                 break;
    case akbd_Fn+8:sx0=0;sx1=ncols-1;break;
    case akbd_Fn+9:sy0=0;sy1=nrows-1;break;
    case akbd_PrintK:io_pr("printer:",0);break;
    default:return FALSE;
  }
  sheet_box();
  return TRUE;
}

static BOOL unknown(wimp_eventstr *e,void *h)
{ h=h;
  switch(e->e)
  { case wimp_ESEND:case wimp_ESENDWANTACK:
              switch (e->data.msg.hdr.action)
              { case wimp_MDATAOPEN:if(!io_read(0)) return FALSE;
                                    win_settitle(swind,fname);
                                    sheet_home();
                                    barclick(0);
                                    return TRUE;
                case wimp_MDATALOAD:if(!io_read(1)) return FALSE;
                                    win_settitle(swind,fname);
                                    sheet_home();
                                    barclick(0);
                                    return TRUE;
                case wimp_MPREQUIT:return TRUE;
              }
              break;
  }
  return FALSE;
}

static void resize(char c)
{ dbox d;
  int n,x;
  switch(c)
  { case 1:sheet_newcol();break;
    case 2:sheet_newrow();break;
    case 3:d=dbox_new("size");
           if(d)
           { dbox_setnumeric(d,2,ncols);
             dbox_setnumeric(d,3,nrows);
             dbox_show(d);
             if(dbox_fillin(d)==0)
             { n=dbox_getnumeric(d,2);
               if(n>ncols) ncols=n;
               if(ncols>NCOLS) ncols=NCOLS;
               n=dbox_getnumeric(d,3);
               if(n>nrows) if(flex_extend((flex_ptr)&sheet,4*n*NCOLS))
               { for(x=nrows*NCOLS;x<n*NCOLS;x++) sheet[x]=0;
                 nrows=n;
               }
             }
             dbox_dispose(&d);
           }
           break;
    case 4:sheet_delcol();break;
    case 5:sheet_delrow();break;
  }
  sheet_home();setext();
}

static void wmenuproc(void *wh,char *h)
#define WMENU  "Edit,>Width,Auto,Update,Save,Resize,Copy,Sort,Graph"
#define SMENU  ">Sheet,>Part,>Text"
#define RMENU  "New Col,New Row,>Extend,Del Cols,Del Rows"
#define GMENU  ">Bars,>Line,>Scatter"
{ dbox d;
  int n,i;
  wh=wh;
  switch(h[0])
  { case 1:openedit();break;
    case 2:d=dbox_new("width");
           if(d)
           { dbox_setnumeric(d,1,width[sx0]);
             dbox_show(d);
             if(dbox_fillin(d)==0)
             { n=dbox_getnumeric(d,1);
               for(i=sx0;i<=sx1;i++) width[i]=n;
               sheet_box();sheet_ebox();
               setext();
             }
             dbox_dispose(&d);
           }
           break;
    case 3:autox=!autox;menu_setflags(wmenu,3,autox,0);if(!autox) break;
    case 4:sheet_change();break;
    case 5:switch(h[1])
           { case 1:saveas(SSSTYPE,fname,0,io_save,0,0,0);
             win_settitle(swind,fname);
             break;
             case 2:saveas(SSSTYPE,"Part",0,io_save,0,0,(void*)1);
             break;
             case 3:if(h[2]) saveas(0xFFF,"SheetText",0,io_pr,0,0,0);
                    else io_pr("Printer:",0);
             break;
           }
           break;
    case 6:resize(h[1]);break;
    case 7:sheet_bcopy();fred();break;
    case 8:sheet_sort();fred();break;
    case 9:switch(h[1])
           { case 1:saveas(0xAFF,"Bars",0,graph_bars,0,0,0);
             break;
             case 2:saveas(0xAFF,"Line",0,graph_line,0,0,0);
             break;
             case 3:saveas(0xAFF,"Scatter",0,graph_line,0,0,(void*)1);
             break;
           }
           break;
  }
}

static void barmenuproc(void *wh,char *h)
{ dbox d;
  int n;
  wh=wh;
  switch (h[0])
  { case 1:d=dbox_new("Info");
           if(d)
           { dbox_setfield(d,4,"0.1 "__DATE__);
             dbox_show(d);dbox_fillin(d);
             dbox_dispose(&d);
           }
           break;
    case 2:d=dbox_new("prset");
           if(d)
           { dbox_setnumeric(d,PRWIDTH,prwidth);
             dbox_setfield(d,PRSEP,sep);
             dbox_setnumeric(d,PRREP,repfirst);
             dbox_setnumeric(d,PRMONO,mono);
             for(n=PRA4P;n<=PRREAD;n++) 
                        dbox_setnumeric(d,n,dr_page==n-PRA4P+1);
             dbox_show(d);
             if(dbox_fillin(d)==0)
             { prwidth=dbox_getnumeric(d,PRWIDTH);
               dbox_getfield(d,PRSEP,sep,4);
               repfirst=dbox_getnumeric(d,PRREP);
               mono=dbox_getnumeric(d,PRMONO);
               for(n=PRA4P;n<=PRREAD;n++) if(dbox_getnumeric(d,n))
               dr_page=n-PRA4P+1;
             }
             dbox_dispose(&d);
           }
           break;
    case 3:exit(0);
  }
}

static BOOL init(void)
{ menu tempmenu;
  wimpt_init(PROGNAME);
  res_init(PROGNAME);
  template_init();
  dbox_init();
  flex_init();
  barmenu=menu_new(PROGNAME,">Info,>PrSetup,Quit");
  if(!barmenu) return FALSE;
  baricon("!"PROGNAME,1,barclick);
  if(!event_attachmenu(win_ICONBAR,barmenu,barmenuproc,0)) return FALSE;
  wimpt_noerr(wimp_create_wind(template_syshandle("sheet"),&swind));
  win_register_event_handler(swind,handler,0);
  edbox=dbox_new("edit");
  if(!edbox) return FALSE;
  bwind=dbox_syshandle(edbox);
  dbox_eventhandler(edbox,edhandler,0);
  dbox_raw_eventhandler(edbox,edkeys,0);
  wmenu=menu_new(PROGNAME,WMENU);
  if(!wmenu) return FALSE;
  tempmenu=menu_new("Save",SMENU);
  if(!tempmenu) return FALSE;
  menu_submenu(wmenu,5,tempmenu);
  tempmenu=menu_new("Save",RMENU);
  if(!tempmenu) return FALSE;
  menu_submenu(wmenu,6,tempmenu);
  tempmenu=menu_new("Graph",GMENU);
  if(!tempmenu) return FALSE;
  menu_submenu(wmenu,9,tempmenu);
  if(!event_attachmenu(swind,wmenu,wmenuproc,0)) return FALSE;
  win_register_event_handler(win_ICONBARLOAD,
          (void(*)(wimp_eventstr*,void*))unknown,0);
  win_add_unknown_event_processor(unknown,0);
  win_claim_idle_events(swind);
  if(!sheet_init()) return FALSE;
  visdelay_init();
  return TRUE;
}

int main(int n,char **s)
{ if(!init()) return 1;
  if(n>1)
  { io_load(s[1]);
    win_settitle(swind,fname);
    sheet_home();
    barclick(0);
  }
  for(;;) event_process();
  return 0;
}
