/* c.imagwind1
 */
#include <string.h>
#include "wimp.h"        /*  access to WIMP SWIs                      */
#include "wimpt.h"       /*  wimp task facilities                     */
#include "win.h"         /*  registering window handlers              */
#include "event.h"       /*  poll loops, etc                          */
#include "baricon.h"     /*  putting icon on icon bar                 */
#include "sprite.h"      /*  sprite operations                        */
#include "werr.h"        /*  error reporting                          */
#include "res.h"         /*  access to resources                      */
#include "resspr.h"      /*  sprite resources                         */
#include "flex.h"        /*  dynamic mem alloc from WIMP              */
#include "heap.h"        /*  uses flex to keep heap in a flex block   */
#include "template.h"    /*  reading in template file                 */
#include "bbc.h"         /*  olde-style graphics routines             */
#include "colourtran.h"  /*  interface to colour translation module   */
#include "os.h"          /*  low-level RISCOS access                  */
#include "dbox.h"        /*  dialogue box handling                    */
#include "saveas.h"      /*  data export from dbox by icon dragging   */
#include "visdelay.h"    /*  show the hourglass for delay             */

#include "aim_stdlib.h"
#include <math.h>
#include "image.h"
#include "$.aim_kern.h.mymem"
#include "c_heap.h"


typedef struct {
 short left,
       bottom,
       right,
       top;
 }os_wblock;
 
typedef struct {
   char b[12];
 } par_block;

static spr_details *my_sprite;         /* sprite used for images       */
static int xdivmult, 
           ydivmult, 
           xmagmult, 
           ymagmult;               /* scale to fit window          */
extern sprite_pixtrans trans[256];     /* colour translation table     */
extern int magnmult,
           magndiv; 
extern int wimp_mode;
extern max_image;
extern WINDOW *wp[MAXIM];
extern char * alloc[200];
extern int alloc_ptr,alloc_bottom,alloc_top;
extern char * imname[MAXIM];
extern BOOL compress;
extern void select_trans(wimp_palettestr *p);

extern void histogram_update_window(wimp_redrawstr r);
extern void histogram_open_window(wimp_openstr *o);
extern void init_Histdraw(WINDOW *wp);
extern void histogram_redraw_window(wimp_w handle);

/*************************** SPRITE CREATION *******************************/
int image_recreate_sprite(WINDOW *wp, char * image_name)
{
  int no_panic;

  heap_free(WindowImSprPtr(wp).area); 
  no_panic=image_create_sprite(wp,image_name);
  return(TRUE);
}


 int image_create_sprite(WINDOW *wp,char * image_name)
{
  sprite_ptr ptr;
  int SpriteDim;
  os_error * err;
  SpriteDim=WindowWidth(wp)*WindowHeight(wp)/2+sizeof(sprite_header)+sizeof(sprite_area)+PAL+4000;      
  wprintf("SpriteDim=%d\n",SpriteDim);
  /* --- allocate our own sprite area to hold image display --- */
  WindowImSprPtr(wp).area=(sprite_area *)heap_alloc(SpriteDim*1); 
   if (WindowImSprPtr(wp).area==NULL) 
       {
         werr(0,"Failed to allocate display sprites\r"); 
         return(FALSE);
       }
    sprite_area_initialise(WindowImSprPtr(wp).area, SpriteDim);
  
  /* --- create a sprite within that area --- */

    err=wimpt_complain(sprite_create(WindowImSprPtr(wp).area, image_name,
                   sprite_haspalette, WindowWidth(wp), WindowHeight(wp), SpriteMode));
    
wprintf("errnum=%d\n",err->errnum);
/*      if (err->errnum > 0) */
        if (FALSE)
        {
         werr(0,"Failed create display sprites\r");
         heap_free(WindowImSprPtr(wp).area);
         return(FALSE); 
        }

    WindowImSprPtr(wp).id.tag = sprite_id_name;
    WindowImSprPtr(wp).id.s.name=image_name;

  /* --- select the sprite and get a pointer to it (faster) --- */

    wimpt_complain(sprite_select_rp(WindowImSprPtr(wp).area, &WindowImSprPtr(wp).id, &ptr));
    WindowImSprPtr(wp).id.tag = sprite_id_addr;
    WindowImSprPtr(wp).id.s.addr = ptr;
    wimpt_complain(sprite_removewastage(WindowImSprPtr(wp).area, &WindowImSprPtr(wp).id));
  return(TRUE);
}

/***************************** WINDOW HANDLING *****************************/

 void image_create_displaywin(WINDOW * wp,char *wind_name)
{
  wimp_wind *window;
  template *t;
  extern int OSx,OSy;
  char nm[80];
  int i;
  /* --- find template for our window and create a window from it --- */
    window = template_syshandle("image");
    strncpy(window->title.text,wind_name,12);
    window->ex.x1=WindowWidth(wp)*OSx; /* was 512 */
    window->ex.y0=-WindowHeight(wp)*OSx; /* was 1024 */ 
    wimp_create_wind(window, &wp->image);
  /* --- find template for Histogram and create a window from it --- */
/*    window = template_syshandle("hist"); */
    t=template_copy(template_find("hist"));
    strncpy(nm,wind_name,7);
    strncat(nm," histogram",10);
    wimp_create_wind(&t->window, &WindowHistHandle(wp));
    win_settitle(WindowHistHandle(wp),nm);
    WindowHistElem(wp)=0;

}

 void image_redo_window(wimp_redrawstr r, BOOL more)
{
  int i,j;
  sprite_header * hoofd;
  BOOL            more_to_do = more;
  wimp_redrawstr  new_r = r;
  sprite_factors factors;
  sprite_pixtrans pixtrans[256];
  extern int OSx,OSy;
  j=0;
  for (i=0;i<max_image;i++)
   {
     if (new_r.w == wp[i]->image) { j=i; break; }
   }
  my_sprite=(spr_details*)&wp[j]->image_sprite;
 
  /* --- ask how the WIMP is going to scale our sprite --- */
    wimp_readpixtrans(my_sprite->area, &my_sprite->id, &factors, pixtrans);

  hoofd=(sprite_header *) my_sprite->id.s.addr;

  select_trans(&wp[j]->pal);


  /* --- refresh the window's contents --- */
  if (!compress)
   {
/*
    factors.ydiv *= PINCH/OSy;
*/

    while (more_to_do)
    {
      wimpt_complain(sprite_put_scaled(my_sprite->area, &my_sprite->id,0,
                                       r.box.x0-r.scx, r.box.y1-r.scy-OSx*WindowHeight(wp[j]),&factors,trans));

      wimp_get_rectangle(&new_r, &more_to_do);
    }
   } 
  else
   { 
  /* -- scale the factors according to current window size --- */
    factors.xdiv *= (WindowWidth(wp[j])*OSx);
    factors.ydiv *= (WindowHeight(wp[j])*OSx);
    factors.xmag *= (xmagmult);
    factors.ymag *= (ymagmult);

    while (more_to_do)
    {
      wimpt_complain(sprite_put_scaled(my_sprite->area, &my_sprite->id,0,
                                      r.box.x0, r.box.y0, &factors, trans));

      wimp_get_rectangle(&new_r, &more_to_do);
    }
   }
}



 void image_redraw_window(wimp_w handle)
{
  BOOL  more;
  wimp_redrawstr r;
  wimp_winfo      winfo;
  
  winfo.w = handle;
  wimp_get_wind_info(&winfo);

  /* --- establish factors by which to scale sprite from current --- */
  /* --- window size                                             --- */

  if (compress)
   {
    xmagmult = winfo.info.box.x1 - winfo.info.box.x0;
    ymagmult = winfo.info.box.y1 - winfo.info.box.y0;
   }
 r.w = handle; 

  /* --- do the redraw --- */

  wimp_redraw_wind(&r, &more);

  if (more)
    image_redo_window(r, more);

}

 void image_update_window(wimp_redrawstr r)
{
  wimp_redrawstr new_r = r;
  BOOL  more;

  wimp_update_wind(&new_r, &more);
  if (more)
    image_redo_window(new_r, more);
}
  

 void image_open_window(wimp_openstr *o)
{
  static int old_x, old_y;
  
  /* --- force scroll offsets to 0, since the window always --- */
  /* --- represents the whole display                       --- */
 if (compress)
  {
   o->x = 0;
   o->y = 0;
  }

  wimp_open_wind(o);

  /* --- only do a redraw if the size of the window has changed --- */

    if (old_x != (o->box.x1 - o->box.x0) || old_y != (o->box.y1 - o->box.y0))
    {
      image_redraw_window(o->w);
      old_x = o->box.x1 - o->box.x0;
      old_y = o->box.y1 - o->box.y0;
    }
}  


     
/****************************** EVENT HANDLING *****************************/


 void image_handler(wimp_eventstr *e, void *handle)
{
  WINDOW *wp;
  wimp_caretstr block;
  wimp_dragstr drag;
  wimp_mousestr muis;

  wp=(WINDOW *)handle;
  my_sprite =(spr_details*) &WindowImSprPtr(wp);

  switch (e->e)
  {
    case wimp_ENULL:
      break;

    case wimp_EREDRAW:
      image_redraw_window(e->data.o.w);
      break;

    case wimp_EOPEN:
      image_open_window(&e->data.o);
      break;

    case wimp_ECLOSE:
      wimpt_noerr(wimp_close_wind(e->data.o.w));
      break;

    case wimp_ESEND:
    case wimp_ESENDWANTACK:    
      WimpMessage(&e->data.msg);
                                /* 
                                 * this code checks for mode/palette
                                 * broadcasts
                                 */
      switch(e->data.msg.hdr.action)
      {
        case wimp_PALETTECHANGE:
          wimpt_complain(colourtran_select_table(SpriteMode, 0, -1,
                        (wimp_paletteword *)-1, trans));
          break;

        case wimp_MMODECHANGE:
          wimpt_checkmode();
          wimpt_complain(colourtran_select_table(SpriteMode, 0, -1,
                        (wimp_paletteword *)-1, trans));
          
          break;

        
        default:
          break;
    }

       case wimp_EBUT:
       {
         if(((e->data.but.m.bbits & wimp_BLEFT)||(e->data.but.m.bbits & wimp_BRIGHT))
             && e->data.but.m.i < 0)
          { 
            block.w=WindowHandle(wp);
            block.i=-1;
            block.x=block.y=100;
            block.height=-1;
            block.index=-1;
            wimpt_complain(wimp_set_caret_pos(&block));  
            wimpt_complain(wimp_get_point_info(&muis));
            drag.window=WindowHandle(wp);
            drag.type=6;     /* rotating rubber box drag type */
            drag.box.x0=muis.x;
            drag.box.y0=muis.y;
            drag.box.x1=muis.x;
            drag.box.y1=muis.y;
            drag.parent.x0=0;
            drag.parent.y0=0;
            drag.parent.x1=2*1279;
            drag.parent.y1=1024;
            wimpt_complain(wimp_drag_box(&drag));

          } 
        }
      break;


    default:  /* we're not interested in any other events */
      break;
  }
}

   
void display_image_window(wimp_w handle,spr_details * spd)
{
 wimp_wstate state;
 my_sprite=spd;
               /* Force display window to front */
 wimpt_noerr(wimp_get_wind_state(handle, &state));
 if (wimpt_mode() == wimp_mode)  state.o.behind = -1;
 wimp_open_wind(&state.o);
 image_redraw_window(handle);

}

 void plot_marker(WINDOW *wp,int xpixel,int ypixel)
 {
 PIXEL * vdi;
 int xsize,ysize,x,y,dx;
 int maskv;
 extern int grey_level;

 xsize=(int)WindowWidth(wp);
 ysize=(int)WindowHeight(wp);
 vdi=WindowSwap(wp);
 x=xpixel;
 y=ypixel;
 if (x<0) x=0;
 if (y<0) y=0;
 if (x > xsize) x=xsize;
 if (y > ysize) y=ysize;
 dx=(x+xsize*y)/2; /* We are deling with nibbles */
 maskv=0xBB;
 if (grey_level == 16) maskv=0xFF;
 /* Make cross */
 *(vdi+dx)=maskv;
/*
 if (x>0) *(vdi+(dx-1))=maskv;
 if (x<(xsize-2)) *(vdi+(dx+1))=maskv;
 if (y>0) *(vdi+(dx-xsize/2))=maskv;
 if (y<(ysize-2)) *(vdi+(dx+xsize/2))=maskv;
*/
}

 void image_read_pixel(WINDOW *wp,int *x,int *y)
 {
  char *poll_loop(char * string,int,wimp_eventstr *);
  wimp_winfo winfo;
  char cmdstr[256],*ptrcmd;
  wimp_eventstr evnt;
  wimp_redrawstr red;
  par_block par;
  wimp_w handle;
  int ymag,xmag,x0,y0;
  extern int OSx,OSy;

  handle=wp->image;
  winfo.w = handle;
  wimp_get_wind_info(&winfo);

  xmag = winfo.info.box.x1 - winfo.info.box.x0;
  ymag = winfo.info.box.y1 - winfo.info.box.y0;
/* set mousebounding box equal to imagewindow outline */
      red.w=handle;
      wimpt_complain(wimp_getwindowoutline(&red));
      red.box.x1-=44;
      red.box.y0+=44;
      red.box.y1-=44;
      par.b[0]=(char)1;
      par.b[1]=(char)red.box.x0 &0xFF;
      par.b[2]=(char)((red.box.x0 &0xFF00) >> 8);
      par.b[3]=(char)red.box.y0 &0xFF;
      par.b[4]=(char)((red.box.y0 &0xFF00) >> 8);
      par.b[5]=(char)red.box.x1 &0xFF;
      par.b[6]=(char)((red.box.x1 &0xFF00) >> 8);
      par.b[7]=(char)red.box.y1 &0xFF;
      par.b[8]=(char)((red.box.y1 &0xFF00) >> 8);
      wimpt_complain(os_word(21,(void *)&par));
/* get mouse coordinates */
      ptrcmd=poll_loop(cmdstr,1,&evnt);
      if (evnt.data.but.m.x <0) 
       { 
        *x=evnt.data.but.m.x; 
       }
      else
       {
        x0=(evnt.data.but.m.x-red.box.x0+winfo.info.scx)/OSx;
        y0=(evnt.data.but.m.y-red.box.y1+winfo.info.scy)/OSy;
        if (compress)
          {
           *x=x0*WindowWidth(wp)*2/xmag;
           *y=-y0*WindowHeight(wp)*4/ymag;
          }
        else
          {
           *x=x0*(2/OSx);
           *y=-y0*(4/OSy);
          }
        plot_marker(wp,*x,*y);

        red.box.x0=(x0-4)*OSx;
        red.box.x1=red.box.x0+12*OSx;
        red.box.y1=(y0+4)*OSy;
        red.box.y0=red.box.y1-12*OSy;
        image_update_window(red);
       }

/* reset mouse bounding box to infinity */
     par.b[0]=(char)1;
      par.b[1]=(char)0;
      par.b[2]=(char)0x80;
      par.b[3]=(char)0;
      par.b[4]=(char)0x80;
      par.b[5]=(char)0xFF;
      par.b[6]=(char)0x7F;
      par.b[7]=(char)0xFF;
      par.b[8]=(char)0x7F;
      wimpt_complain(os_word(21,(void *)&par));
 } 

/*************************** Image Pool declaration ************************/
WINDOW *Create_ImagePool(int x, int y, char * name)
{
  int no_panic;
  void image_menu_proc(void *handle,char * hit);
  WINDOW * wind_create(int Width,int Height);
  void image_handler(wimp_eventstr *e, void *handle);
  void histogram_handler(wimp_eventstr *e, void *handle);
  void histogram_menu_proc(void *handle,char *hit);
  extern menu imgmenu,hsit;
  WINDOW * wp;   

  wp=wind_create(x,y);
  if (wp==NULL) werr(1,"Unable to create Image pool");
  no_panic=image_create_sprite(wp,name);
  if (no_panic == FALSE) werr(1,"Unable to create sprite pool");
  image_create_displaywin(wp,name);
  win_register_event_handler(wp->image,image_handler,
                            (void *)wp);
  event_attachmenu(wp->image,imgmenu,image_menu_proc,0);
  strncpy(ImageName(wp),name,39);
  win_register_event_handler(WindowHistHandle(wp),histogram_handler,
                            (void *)&wp->image_sprite);
  event_attachmenu(WindowHistHandle(wp),hsit,histogram_menu_proc,(void *)wp);
  WindowDiag(wp).data=NULL;
  WindowDiag(wp).length=0;
  WindowDiag(wp).size=0;
  init_Histdraw(wp);
 return(wp);

}
 

 int Realloc_ImagePool(WINDOW * wp,int Width,int Height, char *name,int restore)
{
  int no_panic;
  unsigned long Size_image;
  wimp_winfo window;
  wimp_redrawstr ext;
  extern int OSx,OSy;
  WINDOW tmp_wnd;

  WindowWidth(&tmp_wnd)= WindowWidth(wp); 
  WindowHeight(&tmp_wnd)=WindowHeight(wp);
  WindowSize(&tmp_wnd)=WindowSize(wp);


  if (restore==FALSE)
   {
    heap_free(WindowImSprPtr(wp).area); 
    heap_free(WindowData(wp));   
   }

  WindowWidth(wp)= Width; 
  WindowHeight(wp)=Height;
  Size_image=WindowSize(wp)=(unsigned long)WindowWidth(wp)*WindowHeight(wp);
  WindowNgrey(wp)=NGREY;
  WindowType(wp)=1;
  WindowDispM(wp)=1;

  WindowData(wp)= (PIXEL*) heap_alloc(Size_image*sizeof(PIXEL));
  if (WindowData(wp)==NULL)
   {
     WindowWidth(wp)= WindowWidth(&tmp_wnd); 
     WindowHeight(wp)=WindowHeight(&tmp_wnd);
     WindowSize(wp)=WindowSize(&tmp_wnd);    
     return(FALSE);
   }

  no_panic=image_create_sprite(wp,name);
  if (no_panic==FALSE)
    {
     heap_free(WindowData(wp));   
     WindowWidth(wp)= WindowWidth(&tmp_wnd); 
     WindowHeight(wp)=WindowHeight(&tmp_wnd);
     WindowSize(wp)=WindowSize(&tmp_wnd);
     Size_image=WindowSize(wp)=(unsigned long)WindowWidth(wp)*WindowHeight(wp);
     werr(0,"Trying to rescue Aim data pool");
     WindowData(wp)= (PIXEL*) heap_alloc(Size_image*sizeof(PIXEL));
     if (WindowData(wp)==NULL)werr(1,"Rescue also Failed. Leaving Aim\r");
     no_panic=image_create_sprite(wp,name);
     if (no_panic==FALSE) werr(1,"Rescue also Failed. Leaving Aim\r");
     return(FALSE);
    }  

  window.w=wp->image; /* Window handle */
  wimpt_complain(wimp_get_wind_info(&window));
  ext.box.x0=window.info.ex.x0;
  ext.box.x1=WindowWidth(wp)*OSx; /* was 512 */
  ext.box.y0=-WindowHeight(wp)*OSx; /* was 1024 */ 
  ext.box.y1=window.info.ex.y1;
  ext.w=wp->image;
  wimpt_complain(wimp_set_extent(&ext)); 
  return(TRUE);

}


 void histogram_handler(wimp_eventstr *e, void *handle)
{
  my_sprite =(spr_details*) handle;
  
  switch (e->e)
  {
    case wimp_ENULL:
      break;

    case wimp_EREDRAW:
      histogram_redraw_window(e->data.o.w);
      break;

    case wimp_EOPEN:
      histogram_open_window(&e->data.o);
      break;

    case wimp_ECLOSE:
      wimpt_noerr(wimp_close_wind(e->data.o.w));
      break;

    case wimp_ESEND:
    case wimp_ESENDWANTACK:    
      WimpMessage(&e->data.msg);
      break;

    case wimp_MMODECHANGE:
      break;
    
    default:  /* we're not interested in any other events */
      break;
  }
}
