# include "Ximage.h"
# define XPIX(x,Rx,S) (x*S + Rx)
# define ZPIX(value,Rz1,Rz2) (value*Rz1 - Rz2)
# define FRAC(a) ((a) - (int)(a))

void CreateZoom24 (Layout *layout, Graphic *graphic, double x, double y) {

  int i, j, ii, jj, extra;
  int i_start, i_end, j_start, j_end;
  int dropback;  /* this is a bit of a kludge... */
  int dx, dy, DX, DY;
  double expand, zoomscale, Rx, Ry;
  int expand_in, expand_out;
  unsigned char *out_pix, *out_pix2, *data;
  unsigned char *in_pix,  *in_pix2;
  unsigned char pixel1[256], pixel2[256], pixel3[256];
  unsigned char pixvalue1, pixvalue2, pixvalue3;
  unsigned long white;
  unsigned char white1, white2, white3;

  dx = layout[0].zoom.dx;
  dy = layout[0].zoom.dy;
  extra = 4 - (dx * 3) % 4;

  if (layout[0].matrix.size == 0) {  /* create a test pattern */
    REALLOCATE (layout[0].zoom.data, char, dy*(3*dx+extra));
    bzero (layout[0].zoom.data, layout[0].zoom.dx*layout[0].zoom.dy);
    layout[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
				       layout[0].zoom.data, layout[0].zoom.dx, layout[0].zoom.dy, 32, 0);
    return;
  }

  for (i = 0; i < 256; i++) { /* set up pixel array */
    pixel1[i] = 0x0000ff & layout[0].cmap[i].pixel;
    pixel2[i] = 0x0000ff & (layout[0].cmap[i].pixel >> 8);
    pixel3[i] = 0x0000ff & (layout[0].cmap[i].pixel >> 16);
  }
  white = layout[0].white;
  white1 = 0x0000ff & white;
  white2 = 0x0000ff & (white >> 8);
  white3 = 0x0000ff & (white >> 16);

  zoomscale = MAX (5, layout[0].expand + 5);
  expand = 1 / zoomscale;
  expand_out = (int) zoomscale;
  expand_in  = 1;

  DX = layout[0].matrix.Naxis[0];
  DY = layout[0].matrix.Naxis[1];
  Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
  Ry = y - expand*(int)(0.5*(dy + 1)) + 1;

  i_start = MIN (MAX (-Rx / expand, (1 - FRAC(Rx)) / expand), dx - expand_out + 1);
  j_start = MIN (MAX (-Ry / expand, (1 - FRAC(Ry)) / expand), dy - expand_out + 1);
  i_end   = MAX (MIN ((DX-Rx) / expand, dx - expand_out + 1), 0);
  j_end   = MAX (MIN ((DY-Ry) / expand, dy - expand_out + 1), 0);
  dropback = expand_out - (i_end - i_start) % expand_out;
  if ((i_end - i_start) % expand_out == 0) dropback = 0;

  data = out_pix = (unsigned char *) layout[0].zoom.data;
  in_pix  = (unsigned char *) (layout[0].matrix.buffer) + DX*(int)MAX(Ry,0) + (int)MAX(Rx,0);

  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/

  if ((i_end < i_start) || (j_end < j_start)) {
    for (j = 0; j < dx*dy; j++, out_pix++) 
      *out_pix = white;
    return;
  } 
  
  /**** fill in bottom area ****/
  for (j = 0; j < j_start; j++) {
    for (i = 0; i < dx; i++, out_pix+=3) {
      out_pix[0] = white1;
      out_pix[1] = white2;
      out_pix[2] = white3;
    }
    out_pix += extra;
  }

  for (j = j_start; j < j_end; j+= expand_out, in_pix += expand_in*DX) {
    out_pix = &data[j*(3*dx+extra)];

    /**** fill in area to the left of the picture ****/
    for (jj = 0; jj < expand_out; jj++) { 
      out_pix2 = out_pix + jj*(3*dx + extra);
      for (i = 0; i < i_start; i++, out_pix2+=3) {
	out_pix2[0] = white1;
	out_pix2[1] = white2;
	out_pix2[2] = white3;
      }
    }
    out_pix += 3*i_start;
    
    /*** fill in the picture region ***/
    in_pix2 = in_pix;
    if (expand_out == 1) {
      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix+=3) {
	out_pix[0] = pixel1[*in_pix2];
	out_pix[1] = pixel2[*in_pix2];
	out_pix[2] = pixel3[*in_pix2];
      }
    }
    else {
      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= 3*expand_out) { 
	pixvalue1 = pixel1[*in_pix2];
	pixvalue2 = pixel2[*in_pix2];
	pixvalue3 = pixel3[*in_pix2];
	out_pix2 = out_pix;
	for (jj = 0; jj < expand_out; jj++, out_pix2+=3*(dx-expand_out)+extra) {
	  for (ii = 0; ii < expand_out; ii++, out_pix2+=3) {
	    out_pix2[0] = pixvalue1; 
	    out_pix2[1] = pixvalue2; 
	    out_pix2[2] = pixvalue3; 
	  }
	}
      }
    }
    out_pix -= 3*dropback;
    
    /**** fill in area to the right of the picture ****/
    for (jj = 0; jj < expand_out; jj++) {
      out_pix2 = out_pix + jj*(3*dx+extra);
      for (i = i_end; i < dx; i++, out_pix2+=3) {
	out_pix2[0] = white1;
	out_pix2[1] = white2;
	out_pix2[2] = white3;
      }
    }
  } 
  
  /*
  if ((j_end - j_start) % expand_out > 0)
    out_pix -= (expand_out - (j_end - j_start) % expand_out);
  */

  out_pix = &data[j_end*(3*dx+extra)];
  /**** fill in top area ****/
  for (j = 0; j < (dy - j_end); j++) {
    for (i = 0; i < dx; i++, out_pix+=3) { 
      out_pix[0] = white1;
      out_pix[1] = white2;
      out_pix[2] = white3;
    }
    out_pix+=extra;
  }

  /*
  out_pix = (unsigned char *) layout[0].zoom.data;
  for (i = 0; i < dx*dy; i++) {
    out_pix[3*i + 0] = white1;
    out_pix[3*i + 1] = white2;
    out_pix[3*i + 2] = white3;
  }
  for (j = 0; j < dy/2; j++) {
    for (i = 0; i < dx; i++) {
      out_pix[j*(extra + 3*dx) + 3*i + 0] = pixel1[10];
      out_pix[j*(extra + 3*dx) + 3*i + 1] = pixel2[10];
      out_pix[j*(extra + 3*dx) + 3*i + 2] = pixel3[10];
    }

  }
  */
  layout[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, 24, ZPixmap, 0, 
					layout[0].zoom.data, layout[0].zoom.dx, layout[0].zoom.dy, 32, 0);
  
}
