
/* Generated by Interface Builder */

#import	<stdio.h>
#import	<stdlib.h>
#import	<string.h>
#import	<libc.h>
#import	<appkit/Text.h>
#import	<appkit/Matrix.h>
#import	<appkit/Form.h>
#import	<appkit/Cell.h>
#import	<appkit/Application.h>
#import	<appkit/OpenPanel.h>
#import	<appkit/graphics.h>
#import	<appkit/tiff.h>
#import	<streams/streams.h>
#import	<sys/file.h>
#import	<sys/vnode.h>
#import	"Mask.h"
#import	"HipsImage.h"

	char	*read_line(FILE *fp,int *size);

@implementation HipsImage:View

+ open:sender
{
	char 	tpath [500];
	char	tfile[500];
	char	*opentypes[2] = {"hips",NULL};
	id	openpanel;
	int 	loop;
    
  self = [super new];
  openpanel = [OpenPanel new];
  [openpanel allowMultipleFiles: NO];
  if([openpanel runModalForTypes:opentypes]) {
    loop = 0;
    while ([openpanel filenames] [loop]) {
      strcpy (tpath, [openpanel directory]); 
      strcpy(tfile,[openpanel filenames] [loop]);
      file = (char *)malloc((strlen(tfile)+1)*sizeof(char));
      strcpy(file,tfile);
      name = (char *)malloc((strlen(tfile)+1)*sizeof(char));
      strncpy(name,file,strlen(file)-5);
      name[strlen(file)-5] = '\0';
      path = (char *)malloc((strlen(tpath)+1)*sizeof(char));
      strcpy(path,tpath);
      [self openfile];
      ++loop;
    }
  }
  return self;
}

- openfile
{
        int     i,j,k=0;
        int     ich;
        int     sz;
        char    *buf;
	char	fullPath[500];
	FILE	*fp;
	NXRect	temprect;

  strcpy(fullPath,path);
  strcat(fullPath,"/");
  strcat(fullPath,file);
  if((fp = fopen(fullPath,"r")) == NULL) 
    return [self errormsg: "Can't open image file"];

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  orig_name = (char *)malloc((strlen(buf)+1)*sizeof(char));
  strcpy(orig_name,buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  seq_name = (char *)malloc((strlen(buf)+1)*sizeof(char));
  strcpy(seq_name,buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  num_frame = atoi(buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  orig_date = (char *)malloc((strlen(buf)+1)*sizeof(char));
  strcpy(orig_date,buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  rows = atoi(buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  cols = atoi(buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  bits_per_pixel = atoi(buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  bit_packing = atoi(buf);

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  pixel_format = atoi(buf);

  seq_history = (char *)malloc(sizeof(char));
  strcpy(seq_history,"\0");
  seq_desc = (char *)malloc(sizeof(char));
  strcpy(seq_desc,"\0");

  if((buf = read_line(fp,&sz)) == NULL) 
    return [self errormsg: "Error reading file"];
  while (sz > 1 && buf[sz-1] == '|' && buf[sz] == '\\' ) {
    seq_history = (char *)realloc(seq_history,(strlen(seq_history)+sz+2)*sizeof( char));
    seq_history = (char *)strcat(seq_history,buf);
    if((buf = read_line(fp,&sz)) == NULL) 
      return [self errormsg: "Error reading file"];
  }
  if(sz > 1) {
    seq_history = (char *)realloc(seq_history,(strlen(seq_history)+sz+2)*sizeof(char));
    seq_history = (char *)strcat(seq_history,buf);
    if((buf = read_line(fp,&sz)) == NULL) 
      return [self errormsg: "Error reading file"];
  }
  while ( strcmp( buf, "." ) ) {
    seq_desc = (char *)realloc(seq_desc,(strlen(seq_desc)+sz+2)*sizeof(char));
    seq_desc = (char *)strcat(seq_desc,buf);
    if((buf = read_line(fp,&sz)) == NULL) 
      return [self errormsg: "Error reading file"];
  }
  if(strcmp(buf,".")) 
    return [self errormsg: "Error reading header"];

  data = (int *)malloc(rows*cols*sizeof(int));
  udata = (int *)malloc(rows*cols*sizeof(int));
  odata = (int *)malloc(rows*cols*sizeof(int));

  switch(pixel_format) {
    case HIPS_PFBYTE:
      if(bits_per_pixel != 8) 
        return [self errormsg: "Can't handle unusual bits per pixel"];
      if(bit_packing != 0) 
        return [self errormsg: "Can't handle bit packing"];
      break;
    default:
      return [self errormsg: "Error reading image"];
  }
  for(i=0;i<rows;i++) {
    for(j=0;j<cols;j++) {
      ich = getc(fp);
      if(ich == EOF) 
        return [self errormsg: "EOF reached prematurely"];
      odata[k] = udata[k] = data[k] = ich;
      k++;
    }
  }
  fclose(fp);
 
  temprect.size.width = cols;  temprect.size.height = rows;
  temprect.origin.x = 0;  temprect.origin.y = 0;
  hipsWindow = [Window newContent:&temprect style:NX_SIZEBARSTYLE backing:NX_BUFFERED buttonMask:NX_ALLBUTTONS defer:NO];
  [[hipsWindow moveTo:400 :250] setFreeWhenClosed: NO];
  [self display];

  return(self);
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
	NXRect	temprect;

  [self getFrame:&temprect];
  temprect.origin.x = 0.0;  temprect.origin.y = 0.0;
  NXImageBitmap(&temprect,             		// Rect
                cols,		   		// pixelsWide
                rows,        			// pixelsHigh
                bits_per_pixel,		 	// bps (bits per sample)
                1,                      	// spp (samples per pixel)
                NX_MESHED,              	// config
                NX_MONOTONICMASK,       	// mask
                [self getcdata],   	     	// data1
                NULL,                   	// data2
                NULL,                   	// data3
                NULL,                   	// data4
                NULL);                  	// data5
  return self;
}

- revert
{
 	int	k;

  for(k=0;k<rows*cols;k++)
    data[k] = odata[k];

  return self;
}

- undo
{
 	int	k;

  for(k=0;k<rows*cols;k++)
    data[k] = udata[k];

  return self;
}

- display
{
  [hipsWindow setTitle: name]; 
  [hipsWindow sizeWindow:cols :rows];
  [hipsWindow makeKeyAndOrderFront:hipsWindow];
  [hipsWindow setContentView: self];
  [hipsWindow display];
  NXPing();
  return self;
}

- writeheader: (FILE *)fp
{
  fprintf(fp,"%s\n",orig_name);
  fprintf(fp,"%s\n",seq_name);
  fprintf(fp,"%d\n",num_frame);
  fprintf(fp,"%s\n",orig_date);
  fprintf(fp,"%d\n",rows);
  fprintf(fp,"%d\n",cols);
  fprintf(fp,"%d\n",bits_per_pixel);
  fprintf(fp,"%d\n",bit_packing);
  fprintf(fp,"%d\n",pixel_format);
  fprintf(fp,"%s\n",seq_history);
  fprintf(fp,"%s\n",seq_desc);
  fprintf(fp,".\n");
  return(self);
}

- save:sender
{
	FILE	*fp;
	int	i;
	char	fullPath[500];

  if(!path || !file)
    [self setPath: self];
  strcpy(fullPath,path);
  strcat(fullPath,"/");
  strcat(fullPath,name);
  strcat(fullPath,".hips");
  if((fp = fopen(fullPath,"w")) == NULL) 
    return [self errormsg: "Can't open file for writing"];
  [self writeheader: fp];
  for(i=0;i<rows*cols;i++) 
    putc(data[i],fp);
  fclose(fp);
 
  return self;
}

- saveToTIFF:sender
{
	NXStream	*fStream;
	int		fDesc;
	char		fullPath[500];
	NXImageInfo	image;

  if(!path || !file)
    [self setPath: self];
  strcpy(fullPath,path);
  strcat(fullPath,"/");
  strcat(fullPath,name);
  strcat(fullPath,".tiff");
  if((fDesc = open(fullPath,O_CREAT | O_TRUNC | O_WRONLY,0644)) == -1) 
    return [self errormsg: "fDesc: Can't open fucking TIFF file for writing"];
  if((fStream = NXOpenFile(fDesc,NX_WRITEONLY)) == NULL) 
    return [self errormsg: "fStream: Can't open TIFF file for writing"];
  image.width = cols;
  image.height = rows;
  image.bitsPerSample = bits_per_pixel;
  image.samplesPerPixel = 1;
  image.planarConfig = NX_MESHED;
  image.photoInterp = NX_MONOTONICMASK;
  NXWriteTIFF(fStream,&image,data);
  NXClose(fStream);
  close(fDesc);

  return self;
}

- saveAs:sender
{
  return [[self setPath: self] save:self];
}


- convolve: (id) mask
{
  	int	i,j,mx,my,dx,dy,r,c,k;
	int	mrows,mcols,msize;
	float	min,max;
	float	**d,**cd;

  [self update];
  mrows = mcols = msize = [mask getsize];
  d = [self getdata:&r :&c];

  cd = (float **)malloc(r*c*sizeof(float *));
  for(k=0;k<r;k++) cd[k] = (float *)malloc(c*sizeof(float));

  max = -37267.0;  min = 37267.0;
  for(i=0;i<r;i++) {
    for(j=0;j<c;j++) {
      cd[i][j] = 0.0;
      for(mx=0, dx=i-msize/2; mx<mrows; mx++, dx++) {
        for(my=0, dy=j-msize/2; my<mcols; my++, dy++) {
          if(dx >= 0 && dy >= 0 && dx < r && dy < c) 
            cd[i][j] += [mask getval:mx :my]*d[dx][dy];
        }
      }
      if(cd[i][j] > max)  max = cd[i][j];
      if(cd[i][j] < min)  min = cd[i][j];
    }
  }
  k=0;
  for(i=0;i<r;i++) {
    for(j=0;j<c;j++) {
      data[k] = (int)(255.0*(cd[i][j] - min)/(max - min));
      k++;
    }
  }

  return self;
}

- invert
{
	int	i,j,k;

  [self update];
  k=0;
  for(i=0;i<rows;i++)
    for(j=0;j<cols;j++) {
      data[k] = 255 - data[k];
      k++;
    }
  return self;
}

- threshold:(int) l :(int) h
{
        int     i,j,k;

  [self update];
  k=0;
  for(i=0;i<rows;i++)
    for(j=0;j<cols;j++) {
      if(data[k] >= l && data[k] <= h)
        data[k] = 255;
      else
        data[k] = 0;
      k++;
    }
  return self;
}

- update
{
	int	k;

  for(k=0; k<rows*cols; k++)
    udata[k] = data[k];

  return self;
}

- setPath:sender
{
	char 	tpath [500];
	char	tfile[500];
	id	savepanel;
    
  savepanel = [SavePanel new];
  if([savepanel runModal]) {
    strcpy (tpath, [savepanel directory]);
    strcpy (tfile, strrchr([savepanel filename],'/'));
    file = (char *)malloc((strlen(tfile)+6)*sizeof(char));
    strcpy(file,tfile);
    name = (char *)malloc((strlen(file)+1)*sizeof(char));
    strcpy(name,file);
    path = (char *)malloc((strlen(tpath)+1)*sizeof(char));
    strcpy(path,tpath);
    [hipsWindow setTitle: name];
  }
  return self;
}


- (id) gethipsWindow
{
  return(hipsWindow);
}


- (char *) getpath
{
	char	*p;

  p = (char *)malloc((strlen(path)+1)*sizeof(char));
  strcpy(p,path);
  return p;
}

- (char *) getfile
{
	char 	*f;

  f = (char *)malloc((strlen(file)+1)*sizeof(file));
  strcpy(f,file);
  return f;
}

- (char *) getname
{
	char 	*n;

  n = (char *)malloc((strlen(name)+1)*sizeof(name));
  strcpy(n,name);
  return n;
}


- (char *) getorig_name
{
	char	*on;

  on = (char *)malloc((strlen(orig_name)+1)*sizeof(char));
  strcpy(on,orig_name);
  return(on);
}

- (char *) getseq_name
{
	char *sn;

  sn = (char *)malloc((strlen(seq_name)+1)*sizeof(char));
  strcpy(sn,seq_name);
  return(sn);
}

- (int) getnum_frame
{
  return(num_frame);
}

- (char *) getorig_date
{
	char	*od;

  od = (char *)malloc((strlen(orig_date)+1)*sizeof(char));
  strcpy(od,orig_date);
  return(od);
}

- (int) getrows
{
  return(rows);
}

- (int) getcols
{
  return(cols);
}

- (int) getbits_per_pixel
{
  return(bits_per_pixel);
}

- (int) getbit_packing
{
  return(bit_packing);
}

- (int) getpixel_format
{
  return(pixel_format);
}

- (char *) getseq_history
{
	char	*sh;

  sh = (char *)malloc((strlen(seq_history)+1)*sizeof(char));
  strcpy(sh,seq_history);
  return(sh);
}

- (char *) getseq_desc
{
	char	*sd;

  sd = (char *)malloc((strlen(seq_desc)+1)*sizeof(char));
  strcpy(sd,seq_desc);
  return(sd);
}

- (char *) getcdata
{
	int	i;
	char 	*d;

  d = (char *)malloc(rows*cols*sizeof(char));
  for(i=0;i<rows*cols;i++) d[i] = data[i];
  return(d);
}

- (int *) getdata
{
	int	i;
	int 	*d;

  d = (int *)malloc(rows*cols*sizeof(int));
  for(i=0;i<rows*cols;i++) d[i] = data[i];
  return(d);
}

- (float **) getdata: (int *)theRows :(int *)theCols
{
	int	k;
	float	**fdata;

  *theRows = rows;
  *theCols = cols;
  
  fdata = (float **)malloc(rows*sizeof(float *));
  for(k=0;k<rows;k++) fdata[k] = (float *)malloc(cols*sizeof(float));

  for(k=0;k<rows*cols;k++)
      fdata[k/rows][k%cols] = (float)(data[k]);
  return fdata;
} 

- free
{
  [hipsWindow close];
  free(orig_name);
  free(seq_name);
  free(orig_date);
  free(orig_name);
  free(seq_history);
  free(seq_desc);
  free(data);
  free(udata);
  free(odata);
  [super free];
  return nil;
}

- errormsg: (char *)msg
{
  NXRunAlertPanel("IMAGE",msg,NULL,NULL,NULL);
  return self;
}

@end

char *read_line(FILE *fp,int *size)
{
        int     i=0, c;
        char    buf[5000];

  c = fgetc(fp);
  while( (c != '\n') && !feof(fp) && (i < 5000)) {
    buf[i++] = c;
    c = fgetc(fp);
  }
  if(!i) {
    buf[0] = ' '; buf[1] = '\0';
  }
  else
    buf[i] = '\0';
  if(feof(fp)) {
    NXRunAlertPanel("HIPS ERROR","EOF reached prematurely",NULL,NULL,NULL);
  }

  *size = strlen(buf);
  return(buf);
}

