/*

   Renal_Conv.java
   (c) GC - 27/02/03
   (c) GC - 05/03/03
   (c) GC - 18/04/03

   Plugin sviluppato per consentire il caricamento di studi scintigrafici
   sequenziali renali, in formato Interfile, effettuati con gammacamera Picker 
   o Adac, la successiva visualizzazione, ed il salvataggio in formato "Cure(c)".

*/

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.util.*;

import ij.*;
import ij.io.*;
import ij.gui.*;
import ij.process.*;
import ij.plugin.*;

// ----------------------------------------------------------------------

public class Renal_Conv implements PlugIn {

//    Costanti per decodifica file renali ...
      
   static final int decodeConstMaxLength = 25;
   static final int stringBufferLength = 4096;

//    Variabili globali ...

// ----------------------------------------------------------------------

	public void run(String arg) {

//    PICKER
//    Hippuran Lungo
      String examTypePickerHipp = "HIPP P";

      String studyIDPickerHippDose = "DOSEHIPPL";
      String studyIDPickerHippSeq = "SEQHIPPL";
      String studyIDPickerHippLat = "LATHIPPL";
      
//    DTPA Lungo
      String examTypePickerDTPALungo = "DTPALUNGOP";

      String studyIDPickerDTPALungoDose = "DOSEDTPAL";
      String studyIDPickerDTPALungoSeq = "SEQDTPAL";
      String studyIDPickerDTPALungoLat = "LATDTPAL";

//    DTPA (Breve)
      String examTypePickerDTPA1 = "DTPA P";

      String studyIDPickerDTPADose1 = "DOSEDTPAB";
      String studyIDPickerDTPASeq1 = "SEQDTPAB";

//    ------------------------------------------

//    ADAC
//    Stringhe modificate 18/04/03

//    Hippuran Lungo
//    String examTypeAdacHipp = "HIPP A";
      String examTypeAdacHipp = "HIPPURAN 1";   // Oppure vuoto!

      String studyIDAdacHippDose = "DOSEHIPPL";
//    String studyIDAdacHippSeq = "SEQHIPPL";
      String studyIDAdacHippSeq = "S1 SEQHIPP";
      String studyIDAdacHippSeq2 = "S2 SEQHIPP";
      String studyIDAdacHippLat = "LATHIPPL";
      
//    DTPA Lungo
//    Da verificare!! (18/04/03)
      String examTypeAdacDTPALungo = "DTPALUNGOA";

      String studyIDAdacDTPALungoDose = "DOSEDTPAL";
      String studyIDAdacDTPALungoSeq = "SEQDTPAL";
      String studyIDAdacDTPALungoLat = "LATDTPAL";

//    DTPA (Breve)
//    String examTypeAdacDTPA = "DTPA B";
      String examTypeAdacDTPA = "DTPA  BREV";

//    String studyIDAdacDTPADose = "DOSEDTPAB";
      String studyIDAdacDTPADose = "DOSEDTPA";
//    String studyIDAdacDTPASeq = "SEQDTPAB";
      String studyIDAdacDTPASeq = "S1 SEQDTPA";
      String studyIDAdacDTPALat = "LATDTPAB";

//    -------------------------------

      boolean bRetVal;
      boolean bRes;

      char cCurr;
      int iii;     
      int nLastPointPos = -1;

      int nExtension;
      int nExtensionTry;

      int nIndCurr;
      int nTrial;

      String strTemp;
      String directory;

      String filePureName;
      String fileCompleteName;

      String fileCompleteNameDose = "";
      String fileCompleteNameSeq = "";
      String fileCompleteNameSeq2 = "";
      String fileCompleteNameLat = "";

      String fileNameDose = "";
      String fileNameSeq = "";
      String fileNameSeq2 = "";
      String fileNameLat = "";

      String fileName;
      String fileTry;

      String fileOutDir;
      String fileOutName;
      String fileOutExt;

      String strStudyID;
      String strExamType;
      String strStudyDate;
      String strTotalNumberOfImages;
      String strEnergyWindow;
      String strImageDuration;

      String strExtension;
      String strExtensionTry;
      String strExtensionTmp;

      String strStudyType;
      String strGamma;

      String strStudyIDTry;
      String strStudyDateTry;
      String strEnergyWindowTry;
      String strImageDurationTry;

      String energyWindowDose = "";
      String energyWindowSeq = "";
      String energyWindowSeq2 = "";
      String energyWindowLat = "";

      String totalNumberOfImagesDose = "";
      String totalNumberOfImagesSeq = "";
      String totalNumberOfImagesSeq2 = "";
      String totalNumberOfImagesLat = "";

      String matrixSize1Dose = "";
      String matrixSize1Seq = "";
      String matrixSize1Seq2 = "";
      String matrixSize1Lat = "";

      String matrixSize2Dose = "";
      String matrixSize2Seq = "";
      String matrixSize2Seq2 = "";
      String matrixSize2Lat = "";

      String numberFormat = "";
      String numberOfBytesPerPixel = "";

      String requiredStudyID;

      File fiTry;
     
      while (true) {
         
         IJ.showStatus("Choose a file ...");

   		OpenDialog od = new OpenDialog("Choose a dose or a sequence file ...", arg);
	   	directory = od.getDirectory();
		   String name = od.getFileName();
         fileCompleteName = directory + name;

	   	if (name==null) {
            IJ.showStatus("Done");
		   	return;
         }

   // Decodifica del file prescelto ...

         IJ.showStatus("Decoding selected file ...");

   // Se non c'e' estensione, ovvero se l'estensione non e' numerica, non e' uno studio
   // Picker o Adac ...

         for (iii = 0; iii < name.length(); iii++ ) {
            cCurr = name.charAt(iii);
            if (cCurr == '.') {
               nLastPointPos = iii;
            }
         }

         if (nLastPointPos == -1) {
            IJ.showStatus ("Done");
            IJ.showMessage ("Error", "This is not a Picker/Adac study: " + name + ".");
            continue;                  
         }      

         strExtension = name.substring(nLastPointPos + 1);
         strExtensionTmp = parseInt2(strExtension);
         nExtension = Integer.parseInt(strExtensionTmp);
         if (nExtension == -1)
         {
            IJ.showStatus ("Done");
            IJ.showMessage ("Error", "This is not a Picker/Adac study: " + name + ".");
            continue;                  
         }

         filePureName = name.substring(0, nLastPointPos);     

         for (int jj = 0; jj < strExtension.length(); jj++) {
            if (strExtension.charAt(jj) < '0' || strExtension.charAt(jj) > '9') {
               IJ.showStatus ("Done");
               IJ.showMessage ("Error", "This is not a Picker/Adac study: " + name + ".");               
               continue;                  
            }
         }

   // Per prima cosa si decodifica il campo 'Total number of images': se manca,
   // verosimilmente si e' aperto un file di header ...

         strTotalNumberOfImages = getRenalInfo(fileCompleteName, 3);
         if(strTotalNumberOfImages == null) {
            IJ.showStatus ("Done");
            IJ.showMessage("Error", "This is likely to be a header file: " + name + ".");            
            continue;
         }

   // Attualmente l'unico formato di file supportato (che rappresenta il default per Picker e
   // Adac) e' 'unsigned integer', 2 byte per pixel. Si esce nel caso il formato sia
   // differente o non sia possibile decodificarlo ...

         numberFormat = getRenalInfo(fileCompleteName, 10);
         if (numberFormat != null) {
            if (!numberFormat.equals("unsigned integer")) {
               IJ.showStatus("Done");
               IJ.showMessage("Error", "Number format unsupported: " + numberFormat + ".");               
               continue;
            }
         }
         else {
            IJ.showStatus("Done");
            IJ.showMessage("Error", "Unable to detect number format.");
            continue;
         }

         numberOfBytesPerPixel = getRenalInfo(fileCompleteName, 11);
         if (numberOfBytesPerPixel != null) {
            if (!numberOfBytesPerPixel.equals("2")) {
               IJ.showStatus("Done");
               IJ.showMessage("Error", "Number of bytes per pixel unsupported: " + 
                                       numberOfBytesPerPixel + ".");
               continue;
            }
         }
         else {
            IJ.showStatus("Done");
            IJ.showMessage("Error", "Unable to detect number of bytes per pixel.");
            continue;
         }

   // Se l'utente clicca su un file Picker/Adac utile, si inizia la ricerca del
   // file sequenza corrispondente. In primo luogo, se ne determina lo 'Study ID' in
   // base all''Exam type' ...

         strExamType = getRenalInfo(fileCompleteName, 2);
         if (strExamType != null) {
            strExamType = strExamType.toUpperCase();
            strExamType = strExamType.trim();
         }
         
         if (strExamType.equals("HIPP P")) {
            requiredStudyID = "SEQHIPPL";
         }
         else if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") || 
             strExamType.equals("")) {
            requiredStudyID = "S1 SEQHIPP";
         }
// Verificare!!
         else if (strExamType.equals("DTPALUNGOP") || strExamType.equals("DTPALUNGOA")) {
            requiredStudyID = "SEQDTPAL";
         }
         else if (strExamType.equals("DTPA LUNGO")) {
            requiredStudyID = "S1 SEQDTPA";
         }
         else if (strExamType.equals("DTPA P")) {
            requiredStudyID = "SEQDTPAB";
         }
         else if (strExamType.equals("DTPA A") || strExamType.equals("DTPA  BREV")) {
            requiredStudyID = "S1 SEQDTPA";
         }
         else {
            IJ.showMessage("Error", "Incorrect value for 'Exam type': " + strExamType +
                           ".");
            IJ.showStatus ("Done");
            return;
         }

   // Si decodificano lo 'Study ID' e l''Image duration time' del file corrente: se e'
   // un file sequenza a 5", e' gia' trovato, diversamente lo si ricerca in un loop
   // nel quale si decodificano i file con estensione aumentata in sequenza dei 
   // seguenti valori: -1, 1, -2, 2, -3, 3. Se la ricerca e' infruttuosa, si esce con
   // un errore; altrimenti, in 'fileNameSeq' rimane il nome del file sequenza utile ...

         strStudyID = getRenalInfo(fileCompleteName, 1);
         strStudyID = strStudyID.toUpperCase();
         strImageDuration = getRenalInfo(fileCompleteName, 7);
         if (strImageDuration != null)
            if (strImageDuration.length() > 3)
               strImageDuration = strImageDuration.substring(0, 3);
         strStudyDate = getRenalInfo(fileCompleteName, 4);

         if (!strStudyID.equals(requiredStudyID) || !strImageDuration.equals("5.0")) {

            nIndCurr = -1;
            nTrial = 0;

            while (true) {

               IJ.showStatus("Searching for corresponding sequence file: trial # " + 
                             (++nTrial) + " ...");

               nExtensionTry = nExtension + nIndCurr;
               strExtensionTry = Integer.toString(nExtensionTry);
               strExtensionTry = strExtensionTry.trim();

               fileTry = directory + filePureName + "." + strExtensionTry;
               strStudyIDTry = getRenalInfo(fileTry, 1);
               if (strStudyIDTry != null) {
                  strStudyIDTry = strStudyIDTry.toUpperCase();
                  strStudyIDTry = strStudyIDTry.trim();
               }
               strImageDurationTry = getRenalInfo(fileTry, 7);
               if (strImageDurationTry != null)
                  if (strImageDurationTry.length() > 3)
                     strImageDurationTry = strImageDurationTry.substring(0, 3);
               strStudyDateTry = getRenalInfo(fileTry, 4);
/*
// DEBUG
IJ.showMessage("Debug", "requiredStudyID: " + requiredStudyID + "\n" +
                        "strStudyID: " + strStudyID + "\n" +
                        "strStudyIDTry: " + strStudyIDTry + "\n" +
                        "strStudyDate: " + strStudyDate + "\n" +
                        "strStudyDateTry: " + strStudyDateTry + "\n" +
                        "strImageDuration: " + strImageDuration + "\n" +
                        "strImageDurationTry: " + strImageDurationTry + "\n");
*/
               if (strStudyIDTry != null && strImageDurationTry != null) {
                  if (strStudyIDTry.equals(requiredStudyID) && strImageDurationTry.equals("5.0") &&
                      strStudyDateTry.equals(strStudyDate)) {
                     fileNameSeq = filePureName + "." + strExtensionTry;
                     fileCompleteNameSeq = fileTry;                     
                     nExtension = nExtensionTry;
                     break;
                  }
               }               
         
               if (nIndCurr < 0) {
                  nIndCurr *= (-1);
               }
               else {
                  ++nIndCurr;
                  nIndCurr *= (-1);
               }

               if (Math.abs(nIndCurr) > 3) {
                  IJ.showStatus ("Done");
                  IJ.showMessage("Error", "Sequence file for " + name + " impossible to find.");
                  return;
               }
            }
         }
         else {
            fileCompleteNameSeq = fileCompleteName;
            fileNameSeq = filePureName + "." + strExtension;
         }             
         
         if (requiredStudyID.equals("SEQHIPPL") || requiredStudyID.equals("S1 SEQHIPP"))
            strStudyType = "LONG HIPPURAN";
         else if (requiredStudyID.equals("SEQDTPAL") || requiredStudyID.equals("S1 SEQDTPA"))
            strStudyType = "LONG DTPA";
         else if (requiredStudyID.equals("SEQDTPAB") || requiredStudyID.equals("S1 SEQDTPA"))
            strStudyType = "SHORT DTPA";
         else
            strStudyType = "UNKNOWN";
/*
// DEBUG         
IJ.showMessage("Debug", "Trovato: " + fileCompleteNameSeq);
*/

   // Se si tratta di uno studio ADAC lungo ('Exam type' che vale 'HIPP A' oppure 
   // 'DTPALUNGOA') si cerca il file sequenza a 20" aumentando l'estensione di -1 
   // oppure 1 ...

         if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
             strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
             strExamType.equals("DTPA LUNGO")) {
          
            nIndCurr = -1;
            nTrial = 0;

            if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
                strExamType.equals(""))
//             requiredStudyID = "SEQHIPPL";
               requiredStudyID = "S2 SEQHIPP";
            else if (strExamType.equals("DTPA LUNGO"))
               requiredStudyID = "S2 SEQDTPA";
            else
               requiredStudyID = "SEQDTPAL";

            while (true) {

               IJ.showStatus("Searching for corresponding 20\" sequence file: trial # " + 
                             (++nTrial) + " ...");

               nExtensionTry = nExtension + nIndCurr;
               strExtensionTry = Integer.toString(nExtensionTry);
               strExtensionTry = strExtensionTry.trim();

               fileTry = directory + filePureName + "." + strExtensionTry;
               strStudyIDTry = getRenalInfo(fileTry, 1);
               if (strStudyIDTry != null) {
                  strStudyIDTry = strStudyIDTry.toUpperCase();
                  strStudyIDTry = strStudyIDTry.trim();
               }
               strImageDurationTry = getRenalInfo(fileTry, 7);
               if (strImageDurationTry != null)
                  if (strImageDurationTry.length() > 4)
                     strImageDurationTry = strImageDurationTry.substring(0, 4);
               strStudyDateTry = getRenalInfo(fileTry, 4);
/*
// DEBUG
IJ.showMessage("Debug", "requiredStudyID: >" + requiredStudyID + "<\n" +
                        "strStudyID: " + strStudyID + "\n" +
                        "strStudyIDTry: >" + strStudyIDTry + "<\n" +
                        "strStudyDate: " + strStudyDate + "\n" +
                        "strStudyDateTry: " + strStudyDateTry + "\n" +
                        "strImageDuration: " + strImageDuration + "\n" +
                        "strImageDurationTry: " + strImageDurationTry + "\n");
*/
               if (strStudyIDTry != null && strImageDurationTry != null) {
/*
// DEBUG
IJ.showMessage("Debug", "Uguale strStudyID: " + strStudyIDTry.equals(requiredStudyID) +
               " - Uguale duration: " + strImageDurationTry.equals("20.0") +
               " - Uguale data: " + strStudyDateTry.equals(strStudyDate));
*/
                  if (strStudyIDTry.equals(requiredStudyID) && strImageDurationTry.equals("20.0") &&
                      strStudyDateTry.equals(strStudyDate)) {
                     fileNameSeq2 = filePureName + "." + strExtensionTry;
                     fileCompleteNameSeq2 = fileTry;                                       
                     break;
                  }
               }               
         
               if (nIndCurr < 0) {
                  nIndCurr *= (-1);
               }
               else {
                  ++nIndCurr;
                  nIndCurr *= (-1);
               }

               if (Math.abs(nIndCurr) > 2) {
                  IJ.showStatus ("Done");
                  IJ.showMessage("Error", " Second sequence file (20\") for " + name + 
                                 " impossible to find.");
                  return;
               }
            }
         }
         else {
            fileCompleteNameSeq2 = "";
         }         
/*
// DEBUG
if (!fileCompleteNameSeq2.equals(""))
   IJ.showMessage("Debug", "Trovato: " + fileCompleteNameSeq2);
*/

   // Si cerca il file dose aumentando ancora l'estensione di -1 oppure 1 ...

         if (strExamType.equals("HIPP P")) {
            requiredStudyID = "DOSEHIPPL";
         }
         else if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
                   strExamType.equals("")) {
            requiredStudyID = "DOSEHIPPL";
         }
         else if (strExamType.equals("DTPALUNGOP") || strExamType.equals("DTPALUNGOA") ||
                  strExamType.equals("DTPA LUNGO")) {
            requiredStudyID = "DOSEDTPAL";
         }
         else if (strExamType.equals("DTPA P")) {
            requiredStudyID = "DOSEDTPAB";
         }
         else if (strExamType.equals("DTPA A") || strExamType.equals("DTPA  BREV")) {
            requiredStudyID = "DOSEDTPAB";
         }
         else {
            IJ.showStatus ("Done");
            IJ.showMessage("Internal error", "Incorrect value for 'Exam type' " + 
                           "(when searching for dose file): " + strExamType + ".");
            return;
         }
         
         nIndCurr = -1;
         nTrial = 0;

         while (true) {

            IJ.showStatus("Searching for corresponding dose file: trial # " +
                          (++nTrial) + " ...");

            nExtensionTry = nExtension + nIndCurr;
            strExtensionTry = Integer.toString(nExtensionTry);
            strExtensionTry = strExtensionTry.trim();

            fileTry = directory + filePureName + "." + strExtensionTry;
            strStudyIDTry = getRenalInfo(fileTry, 1);
            if (strStudyIDTry != null) {
               strStudyIDTry = strStudyIDTry.toUpperCase();
               strStudyIDTry = strStudyIDTry.trim();
            }
            strStudyDateTry = getRenalInfo(fileTry, 4);
/*
// DEBUG
IJ.showMessage("Debug", "requiredStudyID: " + requiredStudyID + "\n" +
                        "strStudyID: " + strStudyID + "\n" +
                        "strStudyIDTry: " + strStudyIDTry + "\n" +
                        "strStudyDate: " + strStudyDate + "\n" +
                        "strStudyDateTry: " + strStudyDateTry + "\n");
*/                 
            if (strStudyIDTry != null) {
               if (strStudyIDTry.equals(requiredStudyID) && strStudyDateTry.equals(strStudyDate)) {
                  fileNameDose = filePureName + "." + strExtensionTry;
                  fileCompleteNameDose = fileTry;                     
                  break;
               }
            }               
         
            if (nIndCurr < 0) {
               nIndCurr *= (-1);
            }
            else {
               ++nIndCurr;
               nIndCurr *= (-1);
            }

            if (Math.abs(nIndCurr) > 2) {
               IJ.showStatus ("Done");
               IJ.showMessage("Error", "Dose file for " + name + " impossible to find.");
               return;
            }
         }

/*
// DEBUG         
IJ.showMessage("Debug", "Trovato: " + fileCompleteNameDose);
*/

   // Si cerca il file laterale aumentando l'estensione di -1, +1, -2, +2, -3, +3, -4, +4 ...

         if (strExamType.equals("HIPP P")) {
            requiredStudyID = "LATHIPPL";
         }
         else if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
                  strExamType.equals("")) {
            requiredStudyID = "LATHIPPL";
         }
         else if (strExamType.equals("DTPALUNGOP") || strExamType.equals("DTPALUNGOA") ||
                  strExamType.equals("DTPA LUNGO")) {
            requiredStudyID = "LATDTPAL";
         }
         else if (strExamType.equals("DTPA P")) {
            requiredStudyID = "LATHIPPL";
         }
         else if (strExamType.equals("DTPA A") || strExamType.equals("DTPA  BREV")) {
            requiredStudyID = "LATHIPPL";
         }
         else {
            IJ.showStatus ("Done");
            IJ.showMessage("Internal error", "Incorrect value for 'Exam type' " + 
                           "(when searching for lateral file): " + strExamType + ".");
            return;
         }
         
         nIndCurr = -1;
         nTrial = 0;

         while (true) {

            IJ.showStatus("Searching for corresponding lateral file: trial # " +
                          (++nTrial) + " ...");
   
            nExtensionTry = nExtension + nIndCurr;
            strExtensionTry = Integer.toString(nExtensionTry);
            strExtensionTry = strExtensionTry.trim();

            fileTry = directory + filePureName + "." + strExtensionTry;
            strStudyIDTry = getRenalInfo(fileTry, 1);
            if (strStudyIDTry != null) {
               strStudyIDTry = strStudyIDTry.toUpperCase();
               strStudyIDTry = strStudyIDTry.trim();
            }
            strStudyDateTry = getRenalInfo(fileTry, 4);
/*
// DEBUG
IJ.showMessage("Debug", "requiredStudyID: " + requiredStudyID + "\n" +
                        "strStudyID: " + strStudyID + "\n" +
                        "strStudyIDTry: " + strStudyIDTry + "\n" +
                        "strStudyDate: " + strStudyDate + "\n" +
                        "strStudyDateTry: " + strStudyDateTry + "\n");
*/
            if (strStudyIDTry != null) {
               if (strStudyIDTry.equals(requiredStudyID) && strStudyDateTry.equals(strStudyDate)) {
                  fileNameLat = filePureName + "." + strExtensionTry;
                  fileCompleteNameLat = fileTry;                     
                  break;
               }
            }               
         
            if (nIndCurr < 0) {
               nIndCurr *= (-1);
            }
            else {
               ++nIndCurr;
               nIndCurr *= (-1);
            }

            if (Math.abs(nIndCurr) > 4) {
               IJ.showStatus ("Done");
               IJ.showMessage("Error", "Lateral file for " + name + " impossible to find.");
               return;
            }
         }

         break;
      }
/*
// DEBUG         
IJ.showMessage("Debug", "Trovato: " + fileCompleteNameLat);
*/

   // A questo punto i tre (o quattro) file corretti si trovano nelle corrispondenti
   // variabili 'fileNameSeq', 'fileNameDose' e 'fileNameLat' (piu', eventualmente,
   // 'fileNameSeq2' per 'HIPP A' e 'DTPALUNGOA'). 
   
   // Si cercano i valori di alcuni campi accessori da mostrare all'utente ...

      fileCompleteNameDose = fileCompleteNameDose.trim();
      fileCompleteNameSeq = fileCompleteNameSeq.trim();
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO"))
         fileCompleteNameSeq2 = fileCompleteNameSeq2.trim();
      fileCompleteNameLat = fileCompleteNameLat.trim();

      IJ.showStatus("Required files found. Decoding 'Energy window' field ...");

      energyWindowDose = getRenalInfo(fileCompleteNameDose, 6);
      energyWindowSeq = getRenalInfo(fileCompleteNameSeq, 6);
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") || 
          strExamType.equals("DTPA LUNGO"))
         energyWindowSeq2 = getRenalInfo(fileCompleteNameSeq2, 6);
      energyWindowLat = getRenalInfo(fileCompleteNameLat, 6);

      if (energyWindowDose != null) {
         energyWindowDose = parseInt2(energyWindowDose);
         if (energyWindowDose.length() > 3)
            energyWindowDose = energyWindowDose.substring(0, 3);
      }

      if (energyWindowSeq != null) {
         energyWindowSeq = parseInt2(energyWindowSeq);
         if (energyWindowSeq.length() > 3)
            energyWindowSeq = energyWindowSeq.substring(0, 3);
      }

      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO")) {
         if (energyWindowSeq2 != null) {
            energyWindowSeq2 = parseInt2(energyWindowSeq2);
            if (energyWindowSeq2.length() > 3)
               energyWindowSeq2 = energyWindowSeq2.substring(0, 3);
         }
      }

      if (energyWindowLat != null) {
         energyWindowLat = parseInt2(energyWindowLat);
         if (energyWindowLat.length() > 3)
            energyWindowLat = energyWindowLat.substring(0, 3);
      }

      IJ.showStatus("Decoding 'Total number of images' field ...");

      totalNumberOfImagesDose = getRenalInfo(fileCompleteNameDose, 3);
      totalNumberOfImagesSeq = getRenalInfo(fileCompleteNameSeq, 3);
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO"))
         totalNumberOfImagesSeq2 = getRenalInfo(fileCompleteNameSeq2, 3);
      totalNumberOfImagesLat = getRenalInfo(fileCompleteNameLat, 3);

      IJ.showStatus("Decoding 'Matrix size 1' field ...");

      matrixSize1Dose = getRenalInfo(fileCompleteNameDose, 8);
      matrixSize1Seq = getRenalInfo(fileCompleteNameSeq, 8);
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO"))
         matrixSize1Seq2 = getRenalInfo(fileCompleteNameSeq2, 8);
      matrixSize1Lat = getRenalInfo(fileCompleteNameLat, 8);

      IJ.showStatus("Decoding 'Matrix size 2' field ...");

      matrixSize2Dose = getRenalInfo(fileCompleteNameDose, 9);
      matrixSize2Seq = getRenalInfo(fileCompleteNameSeq, 9);
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO"))
         matrixSize2Seq2 = getRenalInfo(fileCompleteNameSeq2, 9);
      matrixSize2Lat = getRenalInfo(fileCompleteNameLat, 9);

      IJ.showStatus("Files decoded ...");

   // Si visualizza una dialog box con i dati descrittivi dei file trovati ...

      if(strExamType.equals("HIPP P") || strExamType.equals("DTPALUNGOP") ||
         strExamType.equals("DTPA P"))
         strGamma = "PICKER";
      else
         strGamma = "ADAC";

         
		GenericDialog gdx = new GenericDialog("Selected Files", IJ.getInstance());

      gdx.addStringField("Name", getRenalInfo(fileCompleteNameSeq, 0), 20);
      gdx.addStringField("Date", strStudyDate, 20);      
      gdx.addStringField("Scanner", strGamma, 20);
      gdx.addStringField("Study", strStudyType, 20);


      gdx.addMessage("Dose");
      gdx.addStringField("File", fileNameDose, 20);
      gdx.addStringField("Isotope", energyWindowDose);
      gdx.addStringField("# Images", totalNumberOfImagesDose);

      gdx.addMessage("Sequence");
      gdx.addStringField("File", fileNameSeq, 20);
      gdx.addStringField("Isotope", energyWindowSeq);
      gdx.addStringField("# Images", totalNumberOfImagesSeq);

      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO")) {
         gdx.addMessage(" 20\" sequence");
         gdx.addStringField("File", fileNameSeq2, 20);
         gdx.addStringField("Isotope", energyWindowSeq2);
         gdx.addStringField("# Images", totalNumberOfImagesSeq2);
      }

      gdx.addMessage("Lateral");
      gdx.addStringField("File", fileNameLat, 20);
      gdx.addStringField("Isotope", energyWindowLat);
      gdx.addStringField("# Images", totalNumberOfImagesLat);

      gdx.showDialog();

		if (gdx.wasCanceled()) {
         IJ.showStatus ("Done");
			return;
      }

      if (energyWindowDose != null) {
         if(!energyWindowDose.equals(energyWindowSeq)) {
            boolean bRisp = IJ.showMessageWithCancel("Warning", "Isotopes for dose and sequence " +
                                     "are different. Continue anyway?");
            if(!bRisp) {
               IJ.showStatus ("Done");
               return;
            }
         }
      }
      
      if (energyWindowSeq != null) {
         if (energyWindowSeq.equals("140"))
            fileOutExt = ".dtp";
         else if (energyWindowSeq.equals("159"))
            fileOutExt = ".hip";
         else if (strStudyType.indexOf("HIPP") != -1)
            fileOutExt = ".hip";
         else if (strStudyType.indexOf("DTPA") != -1)
            fileOutExt = ".dtp";
         else
            fileOutExt = ".int";
      }
      else if (strStudyType.indexOf("HIPP") != -1) {
         fileOutExt = ".hip";
      }
      else if (strStudyType.indexOf("DTPA") != -1) {
         fileOutExt = ".dtp";
      }
      else {
         fileOutExt = ".int";
      }

      IJ.showStatus("Verifying files existence ...");

      File fiSeq = new File (fileCompleteNameSeq);
      if (!fiSeq.exists()) {      
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", 
                         "Sequence file " + fileCompleteNameSeq + " impossible to find.");
         return;
      }

      File fiSeq2 = null;
     
      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO")) {      
         fiSeq2 = new File (fileCompleteNameSeq2);
         if (!fiSeq2.exists()) {      
            IJ.showStatus ("Done");
            IJ.showMessage ("Internal error", 
                            "20\" sequence file " + fileCompleteNameSeq2 + " impossible to find.");
            return;
         }
      }

      File fiDose = new File (fileCompleteNameDose);
      if (!fiDose.exists()){
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", 
                         "Dose file " + fileCompleteNameDose + " impossible to find.");
         return;
      }

      File fiLat = new File (fileCompleteNameLat);
      if (!fiLat.exists()) {      
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", 
                         "Lateral file " + fileCompleteNameLat + " impossible to find.");
         return;
      }

//    Si impostano i parametri generali di lettura dei tre file. Per alcuni di essi
//    vengono inseriti valori di default che vengono modificati automaticamente a
//    seconda della lunghezza del file, e vengono infine presentati in una finestra
//    di dialogo per l'eventuale correzione manuale ...

		FileInfo fi = new FileInfo();

		fi.fileFormat = fi.RAW;
		fi.width = Integer.parseInt(matrixSize1Seq);
		fi.height = Integer.parseInt(matrixSize2Seq);
		fi.offset = 4096;
		fi.nImages = 1;
		fi.gapBetweenImages = 0;   
		fi.intelByteOrder = true;  //intelByteOrder;
//		fi.intelByteOrder = false;  //unixByteOrder;
		fi.whiteIsZero = false;    //blackIsZero;
		fi.fileType = FileInfo.GRAY16_UNSIGNED;

      // Si modificano i parametri di default a seconda della lunghezza del file ...

      switch ((int)fiDose.length()){

         // 64 x 64 x 1

         case 4096:
            fi.offset = 0;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 5120:
            fi.offset = 1024;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 6144:
            fi.offset = 2048;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 8192:        
            fi.fileType = FileInfo.GRAY8;
            break;

         // 128 x 128 x 1

         case 16384:
      		fi.width = 128;
		      fi.height = 128;
            fi.offset = 0;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 17408:
      		fi.width = 128;
		      fi.height = 128;
            fi.offset = 1024;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 18432:
      		fi.width = 128;
		      fi.height = 128;
            fi.offset = 2048;
            fi.fileType = FileInfo.GRAY8;
            break;
         case 20480:
      		fi.width = 128;
      		fi.height = 128;
            fi.fileType = FileInfo.GRAY8;
            break;

         // 64 x 64 x 2

//       case 8192:     Esiste gia' (64 x 64 x 1 + 4096)
         case 9216:
            fi.offset = 1024;
            break;
         case 10240:
            fi.offset = 2048;
            break;
         case 12288:
            break;

         // 128 x 128 x 2

         case 32768:
      		fi.width = 128;
		      fi.height = 128;
            fi.offset = 0;
            break;
         case 33792:
      		fi.width = 128;
		      fi.height = 128;
            fi.offset = 1024;
            break;
         case 34816:
       		fi.width = 128;
		      fi.height = 128;
            fi.offset = 2048;
            break;
        case 36864:
      		fi.width = 128;
		      fi.height = 128;
      }

      int singleFrameDimension = fi.width * fi.height * 2;

      IJ.showStatus("Files format decoded.");

//    Finestra di dialogo per la correzione manuale dei parametri ...

		GenericDialog gd = new GenericDialog("File format", IJ.getInstance());

		gd.addNumericField("Width (pixels):", fi.width, 0);
		gd.addNumericField("Height (pixels):", fi.height, 0);
		gd.addNumericField("Offset (bytes):", fi.offset, 0);
		gd.showDialog();

		if (gd.wasCanceled()) {
         IJ.showStatus ("Done");
			return;
      }

		fi.width = (int)gd.getNextNumber();
		fi.height = (int)gd.getNextNumber();
		fi.offset = (int)gd.getNextNumber();

// In questa versione si suppone che il formato numerico sia sempre 'unsigmed integer' a
// 2 byte per pixel...

      fi.fileType = FileInfo.GRAY16_UNSIGNED;

/*
// DEBUG

IJ.showMessage("Debug", "width: " + fi.width + "\n" +
                        "height: " + fi.height + "\n" +
                        "offset: " + fi.offset + "\n" +
                        "fileType: " + fi.fileType + "\n" +
                        "dim: " + singleFrameDimension);
*/

//    Si apre il file della dose, si crea uno stack vuoto con gli stessi parametri
//    e si aggiunge l'immagine della dose come primo frame dello stack (che sara'
//    poi lo stack dell'immagine convertita) ...

      IJ.showStatus("Opening files and displaying images ...");

      bRes = openImage(fileNameDose, directory, fi);
      if (! bRes) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open dose image.");
         return;         
      }
      ImageWindow iwDose = WindowManager.getCurrentWindow();
      if (iwDose == null) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open dose image.");
         return;                  
      }
      ImagePlus impDose = iwDose.getImagePlus();
      if (impDose == null) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open dose image.");
         return;                  
      }
      impDose.setTitle("Dose");

//    Creazione dello stack vuoto per l'immagine convertita ...

      ImageStack isTotal = impDose.createEmptyStack();
      ImageProcessor ipDose = impDose.getProcessor();
      isTotal.addSlice("", ipDose);

//    Si apre il file della sequenza, si controlla che si tratti effettivamente di una
//    sequenza (almeno due frame), si aggiungono i relativi frame allo stack della
//    immagine convertita, si crea un "montage" della sequenza, lo si visualizza e si 
//    cancella l'immagine originale ...

      fi.nImages = ((int)fiSeq.length() - fi.offset) / singleFrameDimension;
      bRes = openImage(fileNameSeq, directory, fi);
      if (! bRes) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open sequence image.");
         return;         
      }
      ImageWindow iwSeq = WindowManager.getCurrentWindow();
      if (iwSeq == null) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open sequence image.");
         iwDose.close();
         return;         
      }
      ImagePlus impSeq = iwSeq.getImagePlus();
      if (impSeq == null) {
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open sequence image.");
         iwDose.close();
         return;         
      }

      ImageStack isSeq = impSeq.getStack();
      if (isSeq == null){
         IJ.showStatus ("Done");
         IJ.showMessage ("Error", "Less than two frames in sequence file.");
         iwDose.close();
         iwSeq.close();
         return;
      }

      int isSeqSize = isSeq.getSize();
      if (isSeqSize < 1){
         IJ.showStatus ("Done");
         IJ.showMessage ("Error", "Less than two frames in sequence file.");
         iwDose.close();
         iwSeq.close();
         return;
      }

//    Si aggiungono i frame della sequenza allo stack dell'immagine convertita ...

      ImageProcessor currIp;

      for (iii = 1; iii <= isSeqSize; ++iii){
         currIp = isSeq.getProcessor(iii);
         isTotal.addSlice("", currIp);                  
      }

//    Si crea il "montage" della sequenza e lo si visualizza ...

      MontageMaker mm = new MontageMaker();
      int columns = (int) Math.sqrt((double)isSeqSize);
      int rows = columns + 1;
      mm.makeMontage(impSeq, columns, rows, 0.50, 1, isSeqSize, 1, false, false);
      ImageWindow iwMontage = WindowManager.getCurrentWindow();
      ImagePlus impMontage = iwMontage.getImagePlus();

      impMontage.setTitle(filePureName + " - Sequence");
      iwMontage.setLocation(iwDose.getX() + iwDose.getWidth(), iwDose.getY());

//    Si chiude la finestra originale della sequenza ...

      iwSeq.close();

//    Se si tratta di uno studio Adac con 'Exam type' uguale a 'HIPP A' o 'DTPALUNGOA',
//    si apre il file della seconda sequenza, si controlla che si tratti effettivamente di una
//    sequenza (almeno due frame), si aggiungono i relativi frame allo stack della
//    immagine convertita, si crea un "montage" della sequenza, lo si visualizza e si 
//    cancella l'immagine originale ...

      ImageWindow iwMontage2 = null;
      ImagePlus impMontage2 = null;

      if (strExamType.equals("HIPP A") || strExamType.equals("HIPPURAN 1") ||
          strExamType.equals("") || strExamType.equals("DTPALUNGOA") ||
          strExamType.equals("DTPA LUNGO")) {

         fi.nImages = ((int)fiSeq2.length() - fi.offset) / singleFrameDimension;
         bRes = openImage(fileNameSeq2, directory, fi);
         if (! bRes) {
            IJ.showStatus ("Done");
            IJ.showMessage ("Internal error", "Unable to open 20\" sequence image.");
            return;         
         }
         ImageWindow iwSeq2 = WindowManager.getCurrentWindow();
         if (iwSeq == null) {
            IJ.showStatus ("Done");
            IJ.showMessage ("Internal error", "Unable to open 20\" sequence image.");
            iwDose.close();
            iwMontage.close();
            return;         
         }
         ImagePlus impSeq2 = iwSeq2.getImagePlus();
         if (impSeq2 == null) {
            IJ.showStatus ("Done");
            IJ.showMessage ("Internal error", "Unable to open sequence image.");
            iwDose.close();
            iwMontage.close();
            return;         
         }

         ImageStack isSeq2 = impSeq2.getStack();
         if (isSeq2 == null){
            IJ.showStatus ("Done");
            IJ.showMessage ("Error", "Less than two frames in sequence file.");
            iwDose.close();
            iwMontage.close();
            return;
         }

         int isSeqSize2 = isSeq2.getSize();
         if (isSeqSize2 < 1){
            IJ.showStatus ("Done");
            IJ.showMessage ("Error", "Less than two frames in sequence file.");
            iwDose.close();
            iwMontage.close();
            return;
         }

//    Si aggiungono i frame della sequenza allo stack dell'immagine convertita ...

         ImageProcessor currIp2;

         for (iii = 1; iii <= isSeqSize2; ++iii){
            currIp2 = isSeq2.getProcessor(iii);
            isTotal.addSlice("", currIp2);                  
         }

//    Si crea il "montage" della sequenza e lo si visualizza ...

         MontageMaker mm2 = new MontageMaker();
         columns = (int) Math.sqrt((double)isSeqSize2);
         rows = columns + 1;
         mm2.makeMontage(impSeq2, columns, rows, 0.50, 1, isSeqSize2, 1, false, false);
         iwMontage2 = WindowManager.getCurrentWindow();
         impMontage2 = iwMontage2.getImagePlus();

         impMontage2.setTitle(filePureName + " - 20\" Sequence");
         iwMontage2.setLocation(iwMontage.getX() + iwMontage.getWidth(), iwMontage.getY());

//    Si chiude la finestra originale della sequenza ...

         iwSeq2.close();
      }           

//    Si apre il file della laterale e si aggiunge la relativa immagine come ultimo
//    frame dello stack dell'immagine convertita ...

      fi.nImages = 1;
      bRes = openImage(fileNameLat, directory, fi);
      if (! bRes){
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open lateral image.");
         iwDose.close();
         iwMontage.close();
         if (iwMontage2 != null)
            iwMontage2.close();
         return;         
      }     

      ImageWindow iwLat = WindowManager.getCurrentWindow();
      if (iwLat == null){
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open lateral image.");
         iwDose.close();
         iwMontage.close();
         if (iwMontage2 != null)
            iwMontage2.close();
         return;         
      }
      iwLat.setLocation(iwDose.getX(), iwDose.getY() + iwDose.getHeight());
      ImagePlus impLat = iwLat.getImagePlus();
      if (impLat == null){
         IJ.showStatus ("Done");
         IJ.showMessage ("Internal error", "Unable to open lateral image.");
         iwDose.close();
         iwMontage.close();
         if (iwMontage2 != null)
            iwMontage2.close();
         return;         
      }
      
      impLat.setTitle("Lateral");
      ImageProcessor ipLat = impLat.getProcessor();

      isTotal.addSlice("", ipLat);

//    Dallo stack dell'immagine convertita si crea l'immagine stessa ...

      ImagePlus impTot = new ImagePlus ("Converted image", isTotal);
      if (impLat == null){
         IJ.showStatus ("Done");
         IJ.showMessage ("Picker Renal Converter", "Unable to create converted image.");
         iwDose.close();
         iwMontage.close();
         if (iwMontage2 != null)
            iwMontage2.close();
         iwLat.close();
         return;         
      }
      
      ImageWindow iwTot = impTot.getWindow();      
      ImageStack isTot = impTot.getStack();
      ImageProcessor ipTotCurr;

//    Si aggiorna l'immagine convertita, a partire dal suo "ImageProcessor", dopo aver 
//    eventualmente invertito l'ordine dei byte (l'immagine non viene visualizzata perche'
//    non si invoca il metodo "show()") ...

      impTot.updateAndDraw();

//    Si scrive su disco il file dell'immagine convertita in formato Cure(c) ("raw", senza
//    header e, se a 2 byte per pixel, con i byte di ciascun pixel invertiti) ...

      File fiOut = new File ("C:\\Immag");
      if (!fiOut.isDirectory()) {      
         IJ.showMessage ("Warning",
                         "Directory C:\\IMMAG impossible to find. The output file will be " +
                         "written in the current directory.");
         fileOutDir = directory;
      }
      else {
         fileOutDir = "C:\\Immag";
      }   

      String outPath = fileOutDir + "\\" + filePureName + fileOutExt;

//    Qualora l'immagine sia del tipo "16-bit unsigned" (2 byte per pixel), si provvede
//    ad invertire l'ordine dei byte in modo da renderla compatibile con Cure(c) ...

      if (fi.fileType != FileInfo.GRAY8){
         for (iii = 1; iii <= isTot.getSize(); iii++) {
            ipTotCurr = isTot.getProcessor(iii);
            swapShortBytes(ipTotCurr);   
         }         
      }

      boolean retVal = saveAsRawStack(outPath, impTot);

      if (fi.fileType != FileInfo.GRAY8){
         for (iii = 1; iii <= isTot.getSize(); iii++) {
            ipTotCurr = isTot.getProcessor(iii);
            swapShortBytes(ipTotCurr);   
         }         
      }

      IJ.showStatus("Cure file saved.");

      if (retVal){
         boolean bRisp = IJ.showMessageWithCancel("Done", "Cure file saved as " + 
                                                  outPath + ".\n" + "Leave images on desktop?"); 
         if(!bRisp){
            iwDose.close();
            iwMontage.close();
            if (iwMontage2 != null)
               iwMontage2.close();
            iwLat.close();
         }
      }
      else{
         boolean bRisp = IJ.showMessageWithCancel("Error", "Unable to write Cure " +
                                                  "file" + outPath + ".\n" + "Leave images " +
                                                  "on desktop?");
         if(!bRisp){
            iwDose.close();
            iwMontage.close();
            if (iwMontage2 != null)
               iwMontage2.close();
            iwLat.close();
         }
      }

      IJ.showStatus("Done.");
   }

// ----------------------------------------------------------------------

 	public boolean openImage(String fileName, String directory, FileInfo fi) {

//    Apre il file "raw" specificato, con le informazioni contenute in "fi", e ne 
//    visualizza l'immagine in una finestra ...

		fi.fileName = fileName;
		fi.directory = directory;
      FileOpener fo = new FileOpener(fi);
      if (fo == null) {
         return false;
      }
      fo.open();		
      return true;
	}

// ----------------------------------------------------------------------

	public boolean saveAsRawStack(String path, ImagePlus imp) {

//    Salva l'immagine specificata nel file "path", in formato "raw" ...

		FileInfo fi = imp.getFileInfo();
		try {
			ImageWriter file = new ImageWriter(fi);
			OutputStream out = new BufferedOutputStream(new FileOutputStream(path));
			file.write(out);
			out.close();
		}
		catch (IOException e) {
			IJ.showMessage("Error", "Unable to write the file " + path + "\n[" + e + "].");
			return false;
		}
		return true;
	}

// ----------------------------------------------------------------------

	void swapShortBytes(ImageProcessor ip) {

//    Inverte l'ordine dei byte (solo per immagini a 2 byte per pixel) ...

		short[] pixels = (short[])ip.getPixels();
		int value, byte1, byte2;
		for (int i=0; i<pixels.length; i++) {
			value = pixels[i];
			byte1 = value&0xff;
			byte2 = (value>>8)&0xff;
			pixels[i] = (short)(byte1<<8 | byte2);
		}
	}

// ----------------------------------------------------------------------

   void showFilesNotFound (String strDose, String strSeq, String strLat)
   {
      String strFiles = "";
      if(strDose.equals("..."))
         strFiles = "Dose";
      if(strSeq.equals("...")){
         if(strFiles.equals(""))
            strFiles = "Sequenziale";
         else
            strFiles = strFiles + ", Sequenziale";
      }
      if(strLat.equals("...")){
         if(strFiles.equals(""))
            strFiles = "Laterale";
         else
            strFiles = strFiles + ", Laterale";
      }

      IJ.showStatus("Complementary files not found.");

      IJ.showMessage("Error", "The following files " +
                     "are impossible to find:\n\n" + strFiles + ".");                    
   }

// ----------------------------------------------------------------------

   String getRenalInfo(String fileName, int infoType) {

   // Accetta in input il path completo del file Interfile da decodificare e un
   // parametro numerico relativo al campo richiesto ...

      String infoString = "";
      String outString = "";
      StringBuffer strOutput = new StringBuffer(stringBufferLength);

      if(infoType == 0) {
         infoString = "patient name := ";
      }
      else if(infoType == 1) {
         infoString = "study ID := ";
      }
      else if(infoType == 2) {
         infoString = "exam type := ";
      }
      else if(infoType == 3) {
         infoString = "total number of images := ";
      }
      else if(infoType == 4) {
         infoString = "study date := ";
      }
      else if(infoType == 5) {
         infoString = "study time := ";
      }
      else if(infoType == 6) {
         infoString = "energy window [1] := ";
      }
      else if(infoType == 7){
         infoString = "image duration (sec) := ";
      }
      else if(infoType == 8){
         infoString = "matrix size [1] := ";
      }
      else if(infoType == 9){
         infoString = "matrix size [2] := ";
      }
      else if(infoType == 10){
         infoString = "number format := ";
      }
      else if(infoType == 11){
         infoString = "number of bytes per pixel := ";
      }
      else {
         IJ.showMessage("Internal error", "Method 'getRenalInfo'," +
                        "parameter 'infoType' out of range [" + infoType + "].");
         return(null);
      }

      try
      {
         byte[] pInput = ReadFile(fileName);
         if (pInput == null) {
            return(null);
         }

         String strInput = new String(pInput);   
         String newLine = "\n";
         int nPos = 0;
         int nIndex1 = -1;
         int nIndex2 = -1;
         int nStartOutString = 0;         

		   nIndex1 = strInput.indexOf(infoString,nPos);
   		if(nIndex1 < 0){
            outString = null;
            return(outString);
         }
         nIndex2 = strInput.indexOf(newLine,nIndex1);
         nStartOutString = nIndex1 + infoString.length();
         if(nIndex2 < 0){
            nIndex2 = nStartOutString + decodeConstMaxLength;
         }

         outString = strInput.substring(nStartOutString, nIndex2-1);

   		return(outString);
      }

		catch(Exception e)
		{
			IJ.showMessage("Error", 
                        "Method 'getRenalInfo': input/output error [" + 
                        e.getMessage() + "].");
         return(null);
		}

   }

// ----------------------------------------------------------------------

	static public final byte[] ReadFile(String strFile) throws IOException
	{
  		int nSize = 32768;
 		// open the input file stream

      File fiInput = new File (strFile);
      if (! fiInput.exists())
      {
//         IJ.showMessage ("Internal error", "Method 'ReadFile', file " + 
//                         strFile + " impossible to find.");
         return(null);
      }

   	BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(strFile), nSize);
  		byte[] pBuffer = new byte[nSize];
   	int nPos = 0;
	   // read bytes into a buffer
  		nPos += inStream.read(pBuffer,nPos,nSize-nPos);
   	// while the buffer is filled, double the buffer size and read more
	   while(nPos==nSize)
  		{
   		byte[] pTemp = pBuffer;
	   	nSize *= 2;
		   pBuffer = new byte[nSize];
  			System.arraycopy(pTemp,0,pBuffer,0,nPos);
   		nPos += inStream.read(pBuffer,nPos,nSize-nPos);
	   }
      // close the input stream
  		inStream.close();
   	if(nPos==0)
	   {
		   return "".getBytes();
  		}
   	// return data read into the buffer as a byte array
	   byte[] pData = new byte[nPos];
  		System.arraycopy(pBuffer,0,pData,0,nPos);
   	return pData;
   }

// ----------------------------------------------------------------------

   static public String parseInt2 (String inpString)
   {
      StringBuffer outBuffer = new StringBuffer("");
      char currChar;

      inpString = inpString.trim();

      for (int iii=0; iii<inpString.length(); iii++) {
         currChar = inpString.charAt(iii);
         if (currChar >= '0' && currChar <= '9')
            outBuffer.append(currChar);
         else
            break;
      }
      
      String outString = outBuffer.toString();

      if (outString.length() < 1)
         outString = "-1";
      return(outString);
   }

// ----------------------------------------------------------------------

}

// ----------------------------------------------------------------------

/*** EOF ***/


