import cds.aladin.*;
import java.util.Arrays;

public class HistogramEquiv extends AladinPlugin {
   
   public String menu()          { return "Equivalent Histogram"; }
   public String description()   {
      return "PLUGIN TUTORIAL:\n" +
             "This plugin is an example for manipulating the byte pixel buffer.\n" +
             "It will create a copy of current plane image with modified contrast.\n\n" +
             "This plugin can be launched by script via the \"histeq\" command.";
   }   
   public String author()        { return "S. Derriere [CDS]"; }
   public String version()       { return "0.1 - september 2007"; }
   public String url() { return "http://aladin.u-strasbg.fr/"; }
   public String category()      { return "Image"; }
   public String scriptCommand() { return "histeq"; }   
   
   /**
    * 1) Clone image plane via script 
    * 2) Access to the Aladin pixel buffer of this plane
    * 3) Modify these pixels (histeq)
    * 4) Notify Aladin that the pixels have been modified => lost the full pixel access
    */
   public void exec() {
      
      try {
         // Dump the plane of the current image
         String labelImg = aladin.getAladinImage().getLabel();
         aladin.execCommand("copy "+labelImg+" copyOf"+labelImg);
         
         // Direct access to the pixel buffer of the copied image
         AladinData sd = aladin.getAladinData("copyOf"+labelImg);

	 // get pixels from the image copy
 	 double [][] pix = sd.getPixels();
	 int x = sd.getWidth();
	 int y = sd.getHeight();
	 double linPix [] = new double[x*y+1];
	 for (int i=0; i<x; i++) {
	 	for (int j=0; j<y; j++) {
			linPix[i+j*x+1] = pix[i][j];
		}
	 }

	// create the index by increasing pixel values
	 int[] tab = indexx(x*y, linPix);
         
         for (int i=1; i<=x*y; i++) {
		//if (i%1000==0) System.out.println(i+" "+tab[i]+" "+linPix[i]+" "+linPix[tab[i]]);
	 	int idx = tab[i]-1;
	 	pix[(int)(idx%x)][(int)idx/x] =  (double) (65535.0*i/(x*y));
	 }
	 
	 sd.setPixels(pix);
         // Notify Aladin
         sd.bytePixelsModified();
        
      } catch( AladinException e ) {  aladin.warning("Plugin error: "+e.getMessage()); }
   }
   
   // swap 2 indices in an array   
   public void swap(int tab[], int i, int j) {
   	int tmp;
   	tmp = tab[i];
	tab[i] = tab[j];
	tab[j] = tmp;
   }
   
   // returns index for an array
   public int [] indexx(int n, double arr []) {

	  int i, indxt, ir=n, itemp, j, k, l=1;
	  int jstack=0, NSTACK=50, M=7;
	  double a;
	  
	  int [] istack = new int[NSTACK+1];
	  int [] indx = new int[arr.length];
	  for (j=1;j<=n;j++) indx[j]=j;

    	  for(;;) {
    	    if (ir-l < M) {
    	      for (j=l+1;j<=ir;j++) {
    		indxt=indx[j];
    		a=arr[indxt];
    		for (i=j-1;i>=l;i--) {
    		  if (arr[indx[i]] <= a) break;
    		  indx[i+1]=indx[i];
    		}
    		indx[i+1]=indxt;
    	      }
    	      if (jstack == 0) break;
    	      ir=istack[jstack--];
    	      l=istack[jstack--];
    	    } else {
    	      k=(l+ir) >> 1;
    	      swap(indx, k, l+1);
    	      if(arr[indx[l]] > arr[indx[ir]]) {
    		swap(indx, l, ir);
    		  }
    	      if (arr[indx[l+1]] > arr[indx[ir]]) {
    		swap(indx, l+1, ir);
    		  }
    	      if (arr[indx[l]] > arr[indx[l+1]]) {
    		swap(indx, l, l+1);
    		  }
    	      i=l+1;
    	      j=ir;
    	      indxt=indx[l+1];
    	      a=arr[indxt];
    	      for(;;) {
    		do i++; while (arr[indx[i]] < a);
    		do j--; while (arr[indx[j]] > a);
    		if (j < i) break;
    		swap(indx, i, j);
    	      }
    	      indx[l+1]=indx[j];
	      indx[j]=indxt;
	      jstack += 2;
	      if (jstack > NSTACK) aladin.warning("NSTACK too small in indexx");
	      if (ir-i+1 >= j-l) {
	        istack[jstack]=ir;
	        istack[jstack-1]=i;
	        ir=j-1;
	      } else {
	        istack[jstack]=j-1;
	        istack[jstack-1]=l;
	        l=i;
	      }
	    }
	  }
	  return indx;
	}
}
