// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// ximgtoolut.C
//
// Author:               Sameer Nene
// Date:                 09/12/94
// Version:              1.0.0
// Modification History:
//
// Notes:
//   X module for visualization/manipulation of images/vector/eigenvectors
//   
// ----------------------------------------------------------------------------

#define NO_XMSTRINGS

#include "naming.h"
#include "fileiter.h"
#include "ioutil.h"
#include "list.h"
#include "image.h"
#include "imageutil.h"
#include "vector.h"
#include "ximgtool.h"
#include <strstream.h>
#include <string.h>
#include <Xm/Xm.h>

extern void err_dlg(Widget parent, const char *s);

void objectSearchProc(Widget w, XtPointer p1, XtPointer)
{
  char *p2, *p3;
  int f, i, j;
  XmString *files;
  
  XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *)p1) -> dir,
		  XmSTRING_DEFAULT_CHARSET, &p3);
  FileList fl(p3, NULL, Global::d_ldtstat == 1 ? "pgm" : "vec");
  XtFree(p3);
  FileListIter it(fl);
  List<char *> namelist;
  for(i = 0; it; ++it) {
    p2 = strrchr(it(), '/');
    if(p2 != 0) {
      j = NamingScope::getNameLength(p2 + 1);
      p3 = strncpy(new char[j + 1], p2 + 1, j);
      p3[j] = '\0';
      
    }
    else {
      j = NamingScope::getNameLength(it());
      p3 = strncpy(new char[j + 1], it(), j);
      p3[j] = '\0';
    }
    ListIter<char*> it2(namelist);
    for(f = 0; it2; ++it2)
      if(strcmp(it2(), p3) == 0) {
	f = 1;
	break;
      }
    if(f == 0) {
      namelist += p3;
      ++i;
    }
    else
      delete[] p3;
  }
  ListIter<char *> it2(namelist);
  for(j = 0, files = new XmString[i]; it2; ++it2, ++j)
    files[j] = XmStringCreateSimple(it2());
  XtVaSetValues(w,
		XmNfileListItems, files,
		XmNfileListItemCount, i,
		// *Bug* ?? Fixed on 10/17/94 by Sameer
		//XmNdirSpec, NULL, 
		XmNlistUpdated, True,
		NULL);
  for(ListIter<char *> it3(namelist); it3; ++it3) {
    XmStringFree(files[--i]);
    delete[] it3();
  }
  delete[] files;
}

void paint(Widget, XtPointer, XtPointer)
{
  XPutImage(Global::d_display, Global::d_drawin,
	    Global::d_gc, Global::d_ximage, 0, 0, 0, 0,
	    Global::d_ximage -> width,
	    Global::d_ximage -> height);
}

void adjust_ximage(const Image &img)
{
  char buf[256];
  XmString str;
  
  sprintf(buf, "%u x %u", img.getXSize(), img.getYSize());
  str = XmStringCreateSimple(buf);
  XtVaSetValues(Global::d_label3, XmNlabelString, str, NULL);
  XmStringFree(str);
  ImageUtil::setXImage(Global::d_ximage, img, Global::d_ctrans);
  XtVaSetValues(Global::d_darea,
		XmNwidth, img.getXSize(),
		XmNheight, img.getYSize(),
		NULL);
  XResizeWindow(Global::d_display, Global::d_drawin, img.getXSize(),
		img.getYSize());
  paint(0, 0, 0);
}

void adjust_image(const Image &img, Image *current)
{
  int x1, y1, x2, y2;
  Vector v;
  
  if(Global::d_seg == 0) {
    if(Global::d_nsize == 0) {
      if(Global::d_nbright == 0) {
	*current = img;
	return;
      }
      else {
	ImageUtil::ImageToVector(img, &v);
	v /= v();
	ImageUtil::VectorToImage(v, current, img.getXSize(), img.getYSize(),
				 ImageUtil::GAMMA_CORRECT);
      }
    }
    else {
      ImageUtil::NormalizeSize(img, &v, 0, 0, img.getXSize() - 1,
			       img.getYSize() - 1, Global::d_nxsize,
			       Global::d_nysize, Global::d_aspect);
      if(Global::d_nbright == 0)
	ImageUtil::VectorToImage(v, current, Global::d_nxsize,
				 Global::d_nysize);
      else {
	v /= v();
	ImageUtil::VectorToImage(v, current, Global::d_nxsize,
				 Global::d_nysize, ImageUtil::GAMMA_CORRECT);
      }
    }
  }
  else {
    if(Global::d_nsize == 0) {
      if(Global::d_nbright == 0) {
	ImageUtil::FindBoundingBox(img, &x1, &y1, &x2, &y2, Global::d_thresh);
	img.copy(current, x1, y1, x2, y2);
      }
      else {
	ImageUtil::FindBoundingBox(img, &x1, &y1, &x2, &y2, Global::d_thresh);
	ImageUtil::CropImage(img, &v, x1, y1, x2, y2);
	v /= v();
	ImageUtil::VectorToImage(v, current, x2 - x1 + 1, y2 - y1 + 1,
				 ImageUtil::GAMMA_CORRECT);
      }
    }
    else {
      if(Global::d_nbright == 0) {
	ImageUtil::FindBoundingBox(img, &x1, &y1, &x2, &y2, Global::d_thresh);
	ImageUtil::NormalizeSize(img, &v, x1, y1, x2, y2, Global::d_nxsize,
				 Global::d_nysize,
				 Global::d_aspect);
	ImageUtil::VectorToImage(v, current, Global::d_nxsize,
				 Global::d_nysize);
      }
      else {
	ImageUtil::FindBoundingBox(img, &x1, &y1, &x2, &y2, Global::d_thresh);
	ImageUtil::NormalizeSize(img, &v, x1, y1, x2, y2, Global::d_nxsize,
				 Global::d_nysize,
				 Global::d_aspect);
	v /= v();
	ImageUtil::VectorToImage(v, current, Global::d_nxsize,
				 Global::d_nysize, ImageUtil::GAMMA_CORRECT);
      }
    }
  }
}

void adjust_image(const Image &img, Vector *v)
{
  int x1, y1, x2, y2;
  
  if(Global::d_seg == 0) {
    if(Global::d_nsize == 0) {
      ImageUtil::ImageToVector(img, v);
      if(Global::d_nbright != 0)
	*v /= (*v)();
    }
    else {
      ImageUtil::NormalizeSize(img, v, 0, 0, img.getXSize() - 1,
			       img.getYSize() - 1, Global::d_nxsize,
			       Global::d_nysize, Global::d_aspect);
      if(Global::d_nbright != 0)
	*v /= (*v)();
    }
  }
  else {
    ImageUtil::FindBoundingBox(img, &x1, &y1, &x2, &y2, Global::d_thresh);
    if(Global::d_nsize == 0) {
      ImageUtil::CropImage(img, v, x1, y1, x2, y2);
      if(Global::d_nbright != 0)
	(*v) /= (*v)();
    }
    else {
      ImageUtil::NormalizeSize(img, v, x1, y1, x2, y2, Global::d_nxsize,
			       Global::d_nysize, Global::d_aspect);
      if(Global::d_nbright != 0)
	(*v) /= (*v)();
    }
  }
}

void adjust_vector(const Vector &v, Image *img, int xsize, int ysize)
{
  int x1, y1, x2, y2;
  Image tempImage;
  Vector vec;
  
  if(Global::d_seg == 0) {
    if(Global::d_nsize == 0) {
      if(Global::d_nbright == 0)
	ImageUtil::VectorToImage(v, img, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      else
	ImageUtil::VectorToImage(v / v(), img, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
    }
    else {
      if(Global::d_nbright == 0)
	ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      else
	ImageUtil::VectorToImage(v / v(), &tempImage, xsize, ysize, 1);
      ImageUtil::NormalizeSize(tempImage, &vec, 0, 0, xsize - 1, ysize - 1,
			       Global::d_nxsize, Global::d_nysize,
			       Global::d_aspect);
      ImageUtil::VectorToImage(vec, img, Global::d_nxsize, Global::d_nysize);
    }
  }
  else {
    if(Global::d_nsize == 0) {
      if(Global::d_nbright == 0)
	ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      else
	ImageUtil::VectorToImage(v / v(), &tempImage, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      ImageUtil::FindBoundingBox(tempImage, &x1, &y1, &x2, &y2, Global::d_thresh);
      tempImage.copy(img, x1, y1, x2, y2);
    }
    else {
      if(Global::d_nbright == 0)
	ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      else
	ImageUtil::VectorToImage(v / v(), &tempImage, xsize, ysize,
				 ImageUtil::GAMMA_CORRECT);
      ImageUtil::FindBoundingBox(tempImage, &x1, &y1, &x2, &y2, Global::d_thresh);
      ImageUtil::NormalizeSize(tempImage, &vec, x1, y1, x2, y2,
			       Global::d_nxsize, Global::d_nysize,
			       Global::d_aspect);
      ImageUtil::VectorToImage(vec, img, Global::d_nxsize, Global::d_nysize);
    }
  }
}

void adjust_vector(const Vector &v, Vector *vec, int xsize, int ysize)
{
  int x1, y1, x2, y2;
  Image tempImage;
  
  if(Global::d_seg == 0) {
    if(Global::d_nsize == 0) {
      if(Global::d_nbright == 0)
	*vec = v;
      else
	*vec = v / v();
    }
    else {
      ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
			       ImageUtil::GAMMA_CORRECT);
      ImageUtil::NormalizeSize(tempImage, vec, 0, 0, xsize - 1, ysize - 1,
			       Global::d_nxsize, Global::d_nysize,
			       Global::d_aspect);
      if(Global::d_nbright != 0)
	*vec /= (*vec)();
    }
  }
  else {
    if(Global::d_nsize == 0) {
      ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
			       ImageUtil::GAMMA_CORRECT);
      ImageUtil::FindBoundingBox(tempImage, &x1, &y1, &x2, &y2, Global::d_thresh);
      ImageUtil::CropImage(tempImage, vec, x1, y1, x2, y2);
      if(Global::d_nbright != 0)
	*vec /= (*vec)();
    }
    else {
      ImageUtil::VectorToImage(v, &tempImage, xsize, ysize,
			       ImageUtil::GAMMA_CORRECT);
      ImageUtil::FindBoundingBox(tempImage, &x1, &y1, &x2, &y2, Global::d_thresh);
      ImageUtil::NormalizeSize(tempImage, vec, x1, y1, x2, y2,
			       Global::d_nxsize, Global::d_nysize,
			       Global::d_aspect);
      if(Global::d_nbright != 0)
	*vec /= (*vec)();
    }
  }
}

ErrorScope::Error it_next_image()
{
  const char *p2;
  Image *img, current;
  XmString str;
  ErrorScope::Error error;
  
  img = new Image;
  if((error = ImageUtil::PGMGetFromDisk(img, (*Global::d_flit)())) != ErrorScope::OK) {
    delete img;
    return error;
  }
  
  if((p2 = strrchr((*Global::d_flit)(), '/')) == NULL)
    p2 = (*Global::d_flit)();
  else
    ++p2;
  
  str = XmStringCreateSimple((char *)p2);
  XtVaSetValues(Global::d_label1, XmNlabelString, str, NULL);
  XmStringFree(str);
  
  delete Global::d_image;
  Global::d_image = img;
  adjust_image(*img, &current);
  adjust_ximage(current);

  return ErrorScope::OK;
}

ErrorScope::Error it_next_vector()
{
  const char *p2;
  Vector *vec;
  Image current;
  XmString str;
  ErrorScope::Error error;

  vec = new Vector;
  if(Global::d_ldftype == 1) {
    if((error = IOUtil::get(vec, (*Global::d_flit)())) != ErrorScope::OK) {
      delete vec;
      return error;
    }
  }
  else {
    if((error = vec -> getText((*Global::d_flit)())) != ErrorScope::OK) {
      delete vec;
      return error;
    }
  }

  if((p2 = strrchr((*Global::d_flit)(), '/')) == NULL)
    p2 = (*Global::d_flit)();
  else
    ++p2;
  
  str = XmStringCreateSimple((char *)p2);
  XtVaSetValues(Global::d_label1, XmNlabelString, str, NULL);
  XmStringFree(str);

  delete Global::d_vec_p;
  Global::d_vec_p = vec;
  adjust_vector(*vec, &current, Global::d_vxsize, Global::d_vysize);
  adjust_ximage(current);

  return ErrorScope::OK;
}

void it_next_eigenvector()
{
  char buf[256];
  XmString str;
  Image current;

  sprintf(buf, "%u", Global::d_vapos);
  str = XmStringCreateSimple(buf);
  XtVaSetValues(Global::d_label1, XmNlabelString, str, NULL);
  XmStringFree(str);

  adjust_vector((*Global::d_va)[Global::d_vapos], &current,
		Global::d_vxsize, Global::d_vysize);
  adjust_ximage(current);
}
