/*

   GePetOp_.java

   21/02/2001

   Questo plugin carica in ImageJ uno stack di immagini Dicom ottenuto da uno studio
   effettuato sulla PET GE.

   Nello standard GE PET ad ogni singola immagine (slice) dello stack corrisponde un file
   opportunamente denominato. "GePetOp" rinomina i suddetti file in modo che il loro
   ordinamento alfabetico (che viene impiegato da ImageJ nel caricamento dello stack)
   corrisponda all'ordinamento effettivo delle slice.

   Il codice relativo al caricamento delle slice in uno stack e alla successiva visualiz-
   zazione e' mutuato dal metodo di ImageJ che esegue "File / Import / All As Stack" ...

*/

import java.awt.*;
import java.io.*;

import ij.*;
import ij.io.*;
import ij.process.*;
import ij.plugin.*;

// ---------------------------------------------

public class GePetOp_ implements PlugIn {

	public void run(String arg) {

//    Si seleziona un file qualsiasi in una normale dialog box "Open ..." e 
//    si passa la directory al metodo "reorder()" ...

		OpenDialog od = new OpenDialog("Open GE Pet stack...", arg);
		String directory = od.getDirectory();
		String name = od.getFileName();
		if (name==null)
			return;

      reorder(directory);

//    Dopo aver rinominato i file con il metodo "reorder()", si inseriscono i nomi in un 
//    vettore di stringhe ...

		String[] list = new File(directory).list();
		if (list==null)
			return;

//    Il vettore viene sortato ...

		ij.util.StringSorter.sort(list);
		if (IJ.debugMode) IJ.write("FolderOpener: "+directory+" ("+list.length+" files)");
		int width=0,height=0,type=0;
		ImageStack stack = null;
		int n = 0;

//    Una ad una, le slices vengono caricate in una "ImagePlus" e, successivamente,
//    aggiunte allo stack "stack" creato - vuoto - in precedenza ...

		try {
			for (int i=0; i<list.length; i++) {
				ImagePlus imp = new Opener().openImage(directory, list[i]);
				if (imp!=null && stack==null) {
					stack = imp.createEmptyStack();
					width = imp.getWidth();
					height = imp.getHeight();
					type = imp.getType();
				}
				if (stack!=null)
					n = stack.getSize()+1;

				IJ.showStatus(n+"/"+list.length);
				IJ.showProgress((double)n/list.length);

				if (imp==null)
					IJ.write(list[i] + ": unable to open");
				else if (imp.getWidth()!=width || imp.getHeight()!=height)
					IJ.write(list[i] + ": wrong dimensions");
				else if (imp.getType()!=type)
					IJ.write(list[i] + ": wrong type");
				else
					stack.addSlice(imp.getTitle(), imp.getProcessor());

				System.gc();
			}

		} catch(OutOfMemoryError e) {
			IJ.outOfMemory("GE Pet Opener");
			stack.trim();
		}

//    Lo stack, purche' non vuoto, viene convertito in "ImagePlus" e visualizzato per
//    ulteriori elaborazioni ...

		if (stack.getSize()>0)
			new ImagePlus("Stack", stack).show();

		IJ.showProgress(1.0);

//    Ogni plugin fornito con ImageJ a titolo di esempio "registra" la propria classe:
//    cosi' facciamo anche noi ...

		IJ.register(GePetOp_.class);
	}

// ---------------------------------------------

   public static void reorder (String dirName) {

//    "Reorder()" rinomina, quando necessario, i file della directory "directory", in
//    modo che la successiva funzione di caricamento crei uno stack in cui le slice si
//    presentano nell'ordine appropriato ...

      int iii;
      int jjj;
      int nTotFiles = 0;

      boolean retVal, bFound, toRename;
      boolean notCorrectExecution = false;

      int pos1 = 0;
      int pos2 = 0;
      int nSlice;
      int digitStart = 0;
      int digitEnd = 0;

      String sub1, sub2;
      String cSlice, cSliceTmp;
      String nfName;

//    Si crea un oggetto di classe "File" ...

      File d = new File (dirName);

//    La directory deve esistere ed essere abilitata alla scrittura. Si tratta di controlli
//    di errore sostanzialmente superflui, residuo della precedente versione che chiedeva
//    di inserire manualmente il nome della directory da riordinare ...

      if (! d.exists()) {
         IJ.showMessage ("GE Pet Opener", "No such file or directory: " + dirName + ".");
         return;
      }

      if (! d.canWrite()) {
         IJ.showMessage ("GE Pet Opener", "Write protected: " + dirName + ".");
         return;
      }

      if (! d.isDirectory()) {
         IJ.showMessage ("GE Pet Opener", "Not a directory: " + dirName + ".");
         return;
      }

//    In un vettore di stringhe si inseriscono i nomi dei file della directory ...

      String[] files = d.list();

      if (files.length <= 0) {
         IJ.showMessage ("GE Pet Opener", "Directory is empty: " + dirName + ".");
         return;
      }

      IJ.write ("Processing image files in " + dirName + " ... ");

//    Si processano ad uno ad uno i file della directory ...

      for (iii = 0; iii < files.length; iii++) {

         String currFile = files[iii];

//    Gestione di un errore interno che non dovrebbe verificarsi in condizioni 
//    normali ...

         File f = new File (dirName + currFile);
         if (! f.exists()) {
            IJ.showMessage ("GE Pet Opener", "No such file: " + currFile + ".");
            return;
         }

//    Tra i nomi non corrispondenti allo standard GE PET, vengono qui saltati quelli
//    di meo di 10 caratteri e quelli che non cominciano per "Image" ...

         if (currFile.length() < 10) {
            IJ.write ("Not a Dicom image file: " + currFile + " (name length less than 10).");
            notCorrectExecution = true;
            continue;
         }

         sub1 = currFile.substring(0, 5);

         if (!sub1.equals("Image") && !sub1.equals("IMAGE") &&
             !sub1.equals("image")) {
            IJ.write ("Not a Dicom image file: " + currFile + " (name doesn't begin with 'Image').");
            notCorrectExecution = true;
            continue;
         }

//    Si ricerca la posizione della prima eventale cifra del nome del file ...

         bFound = false;        

         for (jjj = 0; jjj<currFile.length(); ++jjj) {

            char cCurr = currFile.charAt(jjj);

            if (Character.isDigit(cCurr)) {

//    Se si trova la prima cifra, simemorizza la sua posizione e si cerca
//    la posizione dell'ultima (che puo' coincidere con la prima) ...

               bFound = true;
               digitStart = jjj;
               digitEnd = jjj;

               while (Character.isDigit(currFile.charAt(++jjj))) {
                  digitEnd++;
               }

               break;
            }
         }

//    Il nome deve contenere almeno una cifra, altrimenti non e' standard GE PET e il
//    file viene saltato ...
    
         if (!bFound) {
            IJ.write ("Not a Dicom image file: " + currFile + " (no digit found in file name).");
            notCorrectExecution = true;
            continue;
         }

//    Si converte la stringa di cifre in numero (che non puo' essere superiore a 999).

         sub2 = currFile.substring(digitStart, digitEnd+1);

         nSlice = Integer.parseInt(sub2);
         if (nSlice > 999) {
            IJ.write ("Not a Dicom image file: " + currFile + " (slice number greater than 999).");
            notCorrectExecution = true;
            continue;
         }

         cSlice = "   ";

//    Se prima della prima cifra c'e' un '-', per ottenere l'ordinamento corretto
//    si deve semplicemente fare il pad a '000' del numero complessivo ...

         if (currFile.charAt(digitStart-1) == '-') {
            cSliceTmp = "000" + nSlice;
            cSlice = "-" + cSliceTmp.substring(cSliceTmp.length() - 3);
         }

//    Se prima della prima cifra c'e' un '+', verosimilmente il file e' gia'
//    stato elaborato da GePetOp e quindi non deve essere cambiato (salvo
//    l'eventuale pad a '000') ...

         else if (currFile.charAt(digitStart-1) == '+') {
            cSliceTmp = "000" + nSlice;
            cSlice = "+" + cSliceTmp.substring(cSliceTmp.length() - 3);
         }

         else {         

//    Se il numero e' '0' oppure '00' oppure '000', la slice occupa la posizione
//    centrale, pertanto diviene in ogni caso '-000' per ottenere il corretto
//    ordinamento ...

            if (sub2.equals("0") || sub2.equals("00") || 
                sub2.equals("000")) {
               cSlice = "-000";
            }

//    Se infine prima della prima cifra non c'e' ne' '+' ne' '-', vuol dire
//    che per ottenere l'ordinamento corretto il file deve essere collocato in
//    ordine inverso nell'ambito dei file consimili (senza '+' ne' '-'), quindi 
//    si sottrae da 1000 il numero, e successivamente si effettua il pad a '000' ...

            else {
               nSlice = 1000-nSlice;
               cSliceTmp = "000" + nSlice;
               cSlice = "+" + cSliceTmp.substring(cSliceTmp.length() - 3);
            }
         }

//    Modifica del nome del file ...

         nfName = dirName + "Image" + cSlice + ".dcm";
         File nf = new File (nfName);
         retVal = f.renameTo (nf);

//    Si emette un messaggio di avvertimento qualora il nuovo nome di file
//    corrisponda a un file gia' esistente ...

         if (retVal)
            IJ.showStatus ("File " + (++nTotFiles) + " (\"" + currFile + 
                           "\") renamed to \"" + nfName + "\" ... ");
         else
            IJ.showStatus ("File \"" + currFile + "\" exists.");
      }

//    Viene emesso un messaggio riassuntivo sul numero di file rinominati. Qualora
//    fossero stati incontrati file fuori standard, ne viene data comunicazione: in 
//    tal caso, infatti, tali file devono essere spostati o cancellati prima di 
//    caricare lo stack in modo corretto ...

      if (nTotFiles != 0)
         IJ.write ("Directory " + dirName + " correctly reordered (" +
                   nTotFiles + " image files).\n");
      else
         IJ.write ("Directory " + dirName + ": no image files to reorder.\n");

      if (notCorrectExecution)
         IJ.write ("Directory " + dirName + ": found non-Dicom image files.\n");

      return;
   }
}

/*** EOF ***/

