#include "saveas.h"
#include "sprite.h"
#include "event.h"
#include "werr.h"
#include "wimpt.h"
#include "menu.h"
#include "win.h"
#include "baricon.h"
#include "flex.h"
#include "dbox.h"
#include "template.h"
#include "trace.h"
#include "res.h"
#include "resspr.h"
#include "bbc.h"
#include "magnify.h"
#include "wimp.h"
#include "drawfdiag.h"
#include "drawfobj.h"
#include "drawmod.h"
#include "xferrecv.h"
#include "xfersend.h"
#include "visdelay.h"
#include <stdlib.h>
#include <string.h>


typedef enum
 {
 Mmain_info=1,Mmain_zoom,Mmain_save,Mmain_quit
 } Mmain;

struct
 {
 wimp_w Wmain,Wsave;
 menu Mmain,Mmain_s;
 BOOL loaded;
 draw_diag draw;
 char title[256];
 char save[256];
 dbox Winfo;
 int magmul,magdiv;
 } X;

extern BOOL quit = FALSE;



void draw_to_sprite(sprite_area *sarea,int *id)
 {
 int r0,r1,r2,r3;
 wimp_redrawstr r;
 wimp_winfo w;
 draw_diag *d = &X.draw;
 draw_error error;
 double mag = (double) X.magmul / (double) X.magdiv;
 w.w = X.Wmain;
 wimp_get_wind_info(&w);
 r.w = w.w;
 w.info.box.x1 -= w.info.box.x0;
 w.info.box.y1 -= w.info.box.y0;
 w.info.box.x0 = 0;
 w.info.box.y0 = 0;
 r.box = r.g = w.info.box;
 r.scx = w.info.scx;
 r.scy = w.info.scy;
 bbc_move(0,0);
 os_swi4r(0x2e,0x13c,(int) sarea,(int) id,0,&r0,&r1,&r2,&r3);
 draw_render_diag(d,(draw_redrawstr *)&r,mag,&error);
 os_swi4(0x2e,r0,r1,r2,r3);
 }



BOOL save_sprite(char *file,void *h)
 {
 sprite_area *sarea;
 sprite_id id;
 sprite_ptr *ptr;
 flex_ptr anchor;
 int dx = wimpt_dx(),dy = wimpt_dy();
 int xs,ys;
 wimp_wstate wos;
 char leaf[13] = "drawsprite";
 strcpy(X.save,file);
 wimpt_complain(wimp_get_wind_state(X.Wmain,&wos));
 if (h);
 saveas_read_leafname_during_send(leaf,13);
 id.s.name = leaf;
 id.tag = sprite_id_name;
 xs = (wos.o.box.x1 - wos.o.box.x0) / dx + 1;
 ys = (wos.o.box.y1 - wos.o.box.y0) / dy + 1;
 if (!flex_alloc(anchor,xs*ys*2+1024))
   {
   werr(0,"Cannot allocate enough memory for sprite");
   return FALSE;
   }
 sarea = *anchor;
 sarea->sproff = 16;
 sprite_area_initialise(sarea,xs*ys*2+512);
 sprite_create_rp(sarea,leaf,TRUE,xs-1,ys-1,wimpt_mode(),ptr);
 draw_to_sprite(sarea,(int *)*ptr);
 sprite_area_save(sarea,X.save);
 flex_free(anchor);
 return TRUE;
 }



void redraw_win(wimp_w handle)
 {
 int more;
 double mag = (double) X.magmul / (double) X.magdiv;
 wimp_redrawstr r;
 BOOL errors = FALSE;
 BOOL loaded = X.loaded;
 draw_diag *d = &X.draw;
 r.w = handle;
 wimpt_noerr(wimp_redraw_wind(&r,&more));
 while (more)
   {
   draw_error error;
   if (loaded && d->data != NULL)
     {
     if (!draw_render_diag(d,(draw_redrawstr *)&r,mag,&error))
       errors = TRUE;
     }
   wimp_get_rectangle(&r,&more);
   }
 }



void force_redraw(void)
 {
 wimp_redrawstr redraw;
 if (!X.loaded || !X.draw.data) return;
 draw_queryBox(&X.draw,(draw_box *)&redraw.box,TRUE);
#define xw 16
 redraw.box.x0 = redraw.box.x0 * X.magmul / X.magdiv - xw;
 redraw.box.y0 = redraw.box.y0 * X.magmul / X.magdiv - xw;
 redraw.box.x1 = redraw.box.x1 * X.magmul / X.magdiv + xw;
 redraw.box.y1 = redraw.box.y1 * X.magmul / X.magdiv + xw;
 redraw.w = X.Wmain;
 wimpt_noerr(wimp_force_redraw(&redraw));
 }



void event_hand(wimp_eventstr *e,void *handle)
 {
 handle = handle;
 switch (e->e)
   {
   case wimp_ENULL:
     break;
   case wimp_EREDRAW:
     wimpt_checkmode();
     redraw_win(e->data.o.w);
     break;
   case wimp_EOPEN:
     wimp_open_wind(&e->data.o);
     break;
   case wimp_ECLOSE:
     wimp_close_wind(e->data.o.w);
     break;
   case wimp_EPTRLEAVE:
     break;
   case wimp_EPTRENTER:
     break;
   case wimp_EBUT:
     break;
   case wimp_EUSERDRAG:
     break;
   case wimp_EKEY:
     break;
   case wimp_EMENU:
     break;
   case wimp_ESCROLL:
     break;
   case wimp_ELOSECARET:
     break;
   case wimp_EGAINCARET:
     break;
   case wimp_ESEND:
   case wimp_ESENDWANTACK:
     break;
   case wimp_EACK:
     break;
   }
 }



void unload(void)
 {
 X.loaded = FALSE;
 menu_setflags(X.Mmain,2,0,1);
 menu_setflags(X.Mmain,3,0,1);
 }



void dispose(void)
 {
 draw_diag *d = &X.draw;
 if (X.loaded && d->data != NULL)
   {
   force_redraw();
   flex_free((flex_ptr) &d->data);
   d->length = 0;
   }
 unload();
 }



void icon_click(wimp_i icon)
 {
 wimp_wstate state;
 icon = icon;
 if (!X.loaded) return;
 wimpt_complain(wimp_get_wind_state(X.Wmain,&state));
 state.o.behind = -1;
 wimpt_noerr(wimp_open_wind(&state.o));
 }



void load_error(void)
 {
 dispose();
 X.title[0] = 0;
 }



BOOL load(void)
 {
 os_filestr file;
 file.action = 255;
 file.name = X.title;
 file.loadaddr = (int)X.draw.data;
 file.execaddr = 0;
 return (wimpt_complain(os_file(&file)) == 0);
 }
  


int file_size(char *f)
 {
 os_filestr file;
 file.action = 5;
 file.name = f;
 if (wimpt_complain(os_file(&file)) != 0) return 0;
 switch (file.action)
   {
   case 0: werr(0,"File not found"); return 0;
   case 2: werr(0,"I cannot load a directory"); return 0;
   }
 if ((file.loadaddr & 0xfff00000) == 0xfff00000)
   return file.start;
 else
   {
   werr(0,"File cannot be loaded");
   return 0;
   }
 }



void load_finish(int size)
 {
 draw_error error;
 if (draw_verify_diag(&X.draw,&error))
   {
   X.draw.length = size;
   X.loaded = TRUE;
   force_redraw();
   }
 else
   {
   werr(0,"Error in verifying Draw file");
   load_error();
   }
 }



BOOL load_check(int ftype,int size)
 {
 if (ftype != 0xaff)
   {
   werr(0,"Not a Draw file");
   return FALSE;
   }
 dispose();
 if (flex_alloc((flex_ptr) &X.draw.data, size))
   return TRUE;
 else
   {
   werr(0,"Unable to allocate memory for new diagram");
   return FALSE;
   }
 }



void load_file(void)
 {
 char *fname;
 int size;
 int ftype = xferrecv_checkinsert(&fname);
 if (strlen(fname) > 256)
   werr(0,"Cannot load file - filename is too long (max = 256 chars)");
 else
   {
   strcpy(X.title,fname);
   size = file_size(fname);
   if (size > 0 && load_check(ftype,size))
     {
     visdelay_begin();
     if (load())
       {
       load_finish(size);
       }
     else
       load_error();
     visdelay_end();
     }
   }
 xferrecv_insertfileok();
 menu_setflags(X.Mmain,2,0,0);
 menu_setflags(X.Mmain,3,0,0);
 }



void set_win(void)
 {
 wimp_redrawstr str;
 draw_queryBox(&X.draw,(draw_box *)&str.box,TRUE);
 str.box.x0 = str.box.x0 * X.magmul / X.magdiv - 16;
 str.box.y0 = str.box.y0 * X.magmul / X.magdiv - 16;
 str.box.x1 = str.box.x1 * X.magmul / X.magdiv + 16;
 str.box.y1 = str.box.y1 * X.magmul / X.magdiv + 16;
 str.w = X.Wmain;
 str.scx = 0;
 str.scy = 0;
 if (str.g.x1 > str.box.x1) str.g.x1 = str.box.x1;
 if (str.g.y1 > str.box.y1) str.g.y1 = str.box.y1;
 wimp_set_extent(&str);
 win_settitle(X.Wmain,X.title);
 }



BOOL icon_select(wimp_w win,wimp_i icon)
 {
 int r;
 wimp_icon i;
 wimp_get_icon_info(win,icon,&i);
 r = i.flags & wimp_ISELECTED;
 if (r == 0) return FALSE;
 else return TRUE;
 }



void redraw_mag(void *h)
 {
 wimp_wstate wos;
 h = h;
 wimp_close_wind(X.Wmain);
 set_win();
 wimp_get_wind_state(X.Wmain,&wos);
 wimp_open_wind(&wos.o);
 force_redraw();
 }



int print_err(char *f, void *h)
 {
 f = f;
 h = h;
 werr(0,"Use the !Paint application to print sprite files");
 return xfersend_printFailed;
 }



void icon_load(wimp_eventstr *e,void *handle)
 {
 wimp_wstate state;
 handle = handle;
 e = e;
 load_file();
 set_win();
 wimpt_complain(wimp_get_wind_state(X.Wmain,&state));
 state.o.behind = -1;
 wimpt_noerr(wimp_open_wind(&state.o));
 }



void icon_menu(void *handle,char *hit)
 {
 handle = handle;
 switch ((Mmain) hit[0])
   {
   case Mmain_info:
     dbox_show(X.Winfo);
     dbox_fillin(X.Winfo);
     dbox_hide(X.Winfo);
     break;
   case Mmain_zoom:
     magnify_select(&X.magmul,&X.magdiv,9,9,redraw_mag,0);
     break;
   case Mmain_save:
     saveas(0xff9,X.save,X.draw.length,save_sprite,0,print_err,0);
     break;
   case Mmain_quit:
     quit = TRUE;
     break;
   }
 }



BOOL create_win(char *name,wimp_w *h)
 {
 wimp_wind *window;
 window = template_syshandle(name);
 window->minsize = 0x00010001;
 if (window == 0) return FALSE;
 return (wimpt_complain(wimp_create_wind(window,h)) == 0);
 }



BOOL init_wimp(void)
 {
 wimpt_init("Draw Grabber");
 flex_init();
 res_init("DrawGrab");
 resspr_init();
 template_init();
 dbox_init();

 baricon("!DrawGrab",(int)resspr_area(),icon_click);
 X.magmul = 1;
 X.magdiv = 1;
 strcpy(X.save,"DrawSprite");

 /* ************** */
 /* create windows */
 /* ************** */

 if (!create_win("main",&X.Wmain)) return FALSE;
 X.Winfo = dbox_new("progInfo");
 dbox_setfield(X.Winfo,1,"!DrawGrab");
 dbox_setfield(X.Winfo,2,"Saves Draw files as Sprites");
 dbox_setfield(X.Winfo,3," Paul Mason, 1992");
 dbox_setfield(X.Winfo,4,"1.00 (27-Oct-1992)");
 win_register_event_handler(X.Wmain,event_hand,&X.Wmain);
 win_register_event_handler(win_ICONBARLOAD,icon_load,0);

 /* ************ */
 /* create menus */
 /* ************ */

 /* X.Mmain_s = menu_new("Options","Opt1,Opt2,Opt3"); */
 X.Mmain = menu_new("DrawGrab",">Info,>Zoom,>Save sprite,Quit");
 /* menu_submenu(X.Mmain,2,X.Mmain_s); */
 menu_setflags(X.Mmain,Mmain_zoom,0,1);
 menu_setflags(X.Mmain,Mmain_save,0,1);
 if (!event_attachmenu(X.Wmain,X.Mmain,icon_menu,0)) return FALSE;
 if (!event_attachmenu(win_ICONBAR,X.Mmain,icon_menu,0)) return FALSE;
                     
 /* ************** */
 /* draw functions */
 /* ************** */

 draw_registerMemoryFunctions(flex_alloc,flex_extend,flex_free);
 X.draw.data = NULL;
 X.draw.data = 0;

 return TRUE;
 }          



void poll(void)
 {
 while (!quit)
   event_process();
 }



int main(void)
 {
 trace_on();
 if (init_wimp() == FALSE) exit(1);
 poll();
 }
