/**
   * Gets the label <code>infoType</code>. It's equivalent to <code>getParameter</code> (<code>
   * infoType</code>). If the LDR is not available an empty <code>String</code> is returned.
   *
   * @param infoType Description of the Parameter
   * @return the data for the requested label.
   */
  public String getAdditionalInformation(String infoType) {
    LabelData set = new LabelData();

    set = getParameter(infoType);

    if (set == null) {
      return "";
    }

    return set.getData();
  }
  public final LabelData getParameter(String wanted) {
    LabelData back = new LabelData();

    back.setLabel(wanted);
    back.setData((String) parameterTable.get(wanted));

    if (back.getData() == null) {
      //            logger.warn("JCAMP label \"" + wanted + "\" does not exist");
      return null;
    }

    return back;
  }
  /**
   * Gets the label for the Y axis. It's equivalent to <code>getParameter</code> ("YUNITS"). If the
   * LDR is not available an empty <code>String</code> is returned.
   *
   * @return the label for the Y axis.
   */
  public final String getYLabel() {
    LabelData set = new LabelData();

    if (dataDecoded) {
      set = getParameter("YUNITS");

      if (set == null) {
        return "";
      }

      return set.getData();
    } else {
      logger.warn("Can't get JCAMP YUNITS label. Data not decoded.");

      return null;
    }
  }
  /**
   * Returns a string of all LDR's (label data records.
   *
   * @return a string of all LDR's (label data records
   */
  public String toString() {
    // HashTable in String umwandeln;
    String s = "";
    Enumeration en;

    // int i=0;
    String dummy;

    LabelData dummy2 = null;
    dummy2 = getParameter("TITLE");

    if (dummy2 == null) {
      dummy2 = new LabelData();
      dummy2.label = "TITLE";
      dummy2.data = "";
    }

    s = s.concat("##" + dummy2.label + "=" + dummy2.data + "\r\n");

    for (en = parameterTable.keys(); en.hasMoreElements(); ) {
      dummy = (String) en.nextElement();

      if (!dummy.equals("TITLE") && !dummy.equals("END")) {
        s = s.concat("##" + dummy + "=" + (String) parameterTable.get(dummy) + "\r\n");
      }

      // i=i+2;
    }

    dummy2 = getParameter("END");

    if (dummy2 == null) {
      dummy2 = new LabelData();
      dummy2.label = "END";
      dummy2.data = "";
    }

    s = s.concat("##" + dummy2.label + "=" + dummy2.data + "\r\n");

    return s;
  }
  /**
   * Gets the <code>double</code> from <code>ld.data</code>.
   *
   * @param ld Description of the Parameter
   * @return The double value
   * @exception NumberFormatException Description of the Exception
   */
  protected final double getDouble(LabelData ld) throws NumberFormatException {
    if (ld == null) {
      return 0.0;
    }

    double dummy = 0;

    try {
      // alle ',' gleich durch '.' ersetzen, sonst gibts eine NumberFormatException
      dummy = (new Double(ld.getData().replace(',', '.'))).doubleValue();
    } catch (NumberFormatException e) {
      if (e.toString().indexOf("empty") >= 0) {
        return 0.0;
      } else {
        throw new NumberFormatException(
            "The Label " + ld.getLabel() + " contains not a valid double value: " + ld.getData());
      }
    }

    return dummy;
  }
  /**
   * Decide which data type this JCAMP data set contains and decodes this data. After decoding the
   * data is available with <code>getXData()</code> and <code>getYData()</code>, if the data
   * contains a spectra.<br>
   * Chemical structures are not supported, until now !
   *
   * @param decodeDataNow if <code>true</code> the data type is estimated and the data is decoded.
   *     if <code>false</code> only the data type is estimated.
   * @exception JCAMPException Description of the Exception
   * @exception NumberFormatException Description of the Exception
   */
  private void decodeData() throws JCAMPException, NumberFormatException {
    if (dataDecoded) {
      return;
    }

    LabelData set;
    int end = 0;
    String s1 = "";

    // which data type ?
    boolean xypairsState = true;
    boolean xydataState = true;
    set = getParameter("XYPAIRS");

    if (set == null) {
      xypairsState = false;
    }

    if (xypairsState) {
      end = set.getData().indexOf("\n", 0);

      if (end == -1) {
        throw new JCAMPException("Carriage return after \"=\" is not allowed");
      }

      s1 = set.getData().substring(0, end).trim();

      if (!s1.equals("(XY..XY)")) {
        xypairsState = false;
      } else {
        dataType = XYPAIRS;
        decodeXYPAIRSandPEAKTABLE();
        dataDecoded = true;

        return;
      }
    }

    if (!xypairsState) {
      set = getParameter("XYDATA");

      if (set == null) {
        xydataState = false;
      }

      if (xydataState) {
        end = set.getData().indexOf("\n", 0);

        if (end == -1) {
          throw new JCAMPException("Carriage return after \"=\" is not allowed");
        }

        s1 = set.getData().substring(0, end).trim();

        if (!s1.equals("(X++(Y..Y))")) {
          xydataState = false;
        } else {
          dataType = XYDATA_X_YY;
          decodeXYDATA();
          dataDecoded = true;

          return;
        }
      }
    }

    /*
     *  if(dataType==XYPAIRS || dataType==XYDATA_X_YY){
     *  if(decodeDataNow){
     *  decodeXYDATAorXYPAIRS();
     *  }
     *  dataDecoded=true;
     *  return;
     *  }
     */
    boolean chemicalStructureState = true;
    set = getParameter("MOLFORM");

    if (set == null) {
      chemicalStructureState = false;
    }

    set = getParameter("ATOMLIST");

    if (set == null) {
      chemicalStructureState = false;
    }

    set = getParameter("BONDLIST");

    if (set == null) {
      chemicalStructureState = false;
    }

    if (chemicalStructureState) {
      dataType = CHEMICAL_STRUCTURE;

      // if(state)decodeChemicalStructure();
      // dataDecoded=true;
      return;
    }

    set = getParameter("XYPOINTS");

    if (set != null) {
      throw new JCAMPException("Data XYPOINTS is not supported ");

      // dataType=XYPOINTS;
      // dataDecoded=true;
      // return;
    }

    set = getParameter("PEAK TABLE");

    if (set != null) {
      end = set.getData().indexOf("\n", 0);

      if (end == -1) {
        throw new JCAMPException("Carriage return after \"=\" is not allowed");
      }

      s1 = set.getData().substring(0, end).trim();

      if (s1.equals("(XY..XY)")) {
        dataType = PEAK_TABLE;
        decodeXYPAIRSandPEAKTABLE();
        dataDecoded = true;

        return;
      }
    }

    set = getParameter("PEAK ASSIGNMENTS");

    if (set != null) {
      throw new JCAMPException("Data PEAK ASSIGNMENTS is not supported ");

      // dataType=PEAK_ASSIGNMENTS;
      // dataDecoded=true;
      // return;
    }

    set = getParameter("RADATA");

    if (set != null) {
      throw new JCAMPException("Data RADATA is not supported ");

      // dataType=RADATA;
      // dataDecoded=true;
      // return;
    }

    set = getParameter("DATA TYPE");

    if (set != null) {
      if (set.getData().trim().equals("LINK")) {
        dataType = LINK;

        // dataDecoded=true;
        return;
      }
    }

    // irgend ein anderer Datentyp
    throw new JCAMPException("Data type not supported ");
  }
 /**
  * Set one LDR (data label record).
  *
  * @param newLDR the new label and the new data
  */
 public final void setParameter(LabelData newLDR) {
   if (newLDR != null) {
     parameterTable.put(newLDR.getLabel(), newLDR.getData());
   }
 }
  /**
   * Decodes XYPAIRS.
   *
   * @exception JCAMPException Description of the Exception
   * @exception NumberFormatException Description of the Exception
   */
  private void decodeXYPAIRSandPEAKTABLE() throws JCAMPException, NumberFormatException {
    LabelData set = new LabelData();
    int begin;
    int end = 0;
    String s1 = "";

    if (dataType == PEAK_TABLE) {
      xFactor = 1.0;
      yFactor = 1.0;
      set = getParameter("PEAK TABLE");

      //            if (set == null)
      //            {
      //            }
    } else {
      set = getParameter("DELTAX");

      if (set == null) {
        calculatedDeltaXneeded = true;
      }

      deltaX = getDouble(set);

      set = getParameter("LASTX");

      if (set == null) {
        String add = "";

        if (!calculatedDeltaXneeded) {
          add = ". The label DELTAX is missing and " + "can not be calculated";
        }

        throw new JCAMPException("The label LASTX is missing" + add);
      }

      lastX = getDouble(set);

      set = getParameter("FIRSTX");

      if (set == null) {
        String add = "";

        if (!calculatedDeltaXneeded) {
          add = ". The label DELTAX is missing and " + "can not be calculated";
        }

        throw new JCAMPException("The label FIRSTX is missing" + add);
      }

      firstX = getDouble(set);

      set = getParameter("NPOINTS");

      if (set == null) {
        String add = "";

        if (!calculatedDeltaXneeded) {
          add = ". The label NPOINTS is missing and DELTAX" + "can not be calculated";
          throw new JCAMPException("The label FIRSTX is missing" + add);
        }

        logger.warn("The label NPOINTS is missing. Now its estimated");
        estimatedNPointsNeeded = true;
      }

      nPoints = getDouble(set);

      // Berechnung von deltaX;
      if (calculatedDeltaXneeded) {
        deltaX = (lastX - firstX) / (nPoints - 1);
      } else {
        double dummy = 0;

        if (!estimatedNPointsNeeded && (nPoints != 0)) {
          // einfach nochmals zur Kontrolle von deltaX. Eigentlich unnoetig !
          dummy = (lastX - firstX) / (nPoints - 1);

          if (Math.abs(dummy - deltaX) > DELTAX_DIFFERENCE_WARNING_VALUE) {
            logger.warn(
                "The calculated DELTAX="
                    + dummy
                    + " (original DELTAX="
                    + deltaX
                    + ") shows a difference above "
                    + DELTAX_DIFFERENCE_WARNING_VALUE);
          }
        }
      }

      set = getParameter("XFACTOR");

      if (set == null) {
        throw new JCAMPException("The label XFACTOR is missing");
      }

      xFactor = getDouble(set);

      set = getParameter("YFACTOR");

      if (set == null) {
        throw new JCAMPException("The label YFACTOR is missing");
      }

      yFactor = getDouble(set);

      set = getParameter("XYPAIRS");

      //            if (set == null)
      //            {
      //            }
    }

    end = set.getData().indexOf("\n", 0);

    if (end == -1) {
      throw new JCAMPException("Carriage return" + " after \"=\" is not allowed");
    }

    s1 = set.getData().substring(0, end).trim();
    s1 = set.getData().substring(end + 1, set.getData().indexOf("\n", end + 1));

    //        StringTokenizer dataValue = new StringTokenizer(s1, " \t");
    xData = new LinkedList();
    yData = new LinkedList();

    begin = 0;
    begin = set.getData().indexOf("\n", begin);
    begin++;

    do {
      end = set.getData().indexOf("\n", begin);

      if (set.getData().indexOf(";", begin) != -1) {
        end = Math.min(end, set.getData().indexOf(";", begin));
      }

      if (end == -1) {
        break;
      }

      s1 = set.getData().substring(begin, end).trim();

      // dataLine
      // println("s1:"+parameterSaetze[1].substring(begin,end));
      addXYPAIRSandPEAKTABLEdataLine(s1);
      begin = end + 1;
    } while (true);

    sendDataToDoubleArray();
  }
  /**
   * Decodes XYDATA. Only the uncompressed ASDF format is supported. The compressed AFFN format is
   * not supported.
   *
   * @exception JCAMPException Description of the Exception
   * @exception NumberFormatException Description of the Exception
   */
  private void decodeXYDATA() throws JCAMPException, NumberFormatException {
    LabelData set = new LabelData();
    int begin;
    int end = 0;
    String s1 = "";
    String s2 = "";

    set = getParameter("DELTAX");

    if (set == null) {
      logger.warn("The label DELTAX is missing. Now its calculated !;-)");
      calculatedDeltaXneeded = true;
    }

    deltaX = getDouble(set);

    set = getParameter("LASTX");

    if (set == null) {
      String add = "";

      if (!calculatedDeltaXneeded) {
        add = ". The label DELTAX is missing and " + "can not be calculated";
      }

      throw new JCAMPException("The label LASTX is missing" + add);
    }

    lastX = getDouble(set);

    set = getParameter("FIRSTX");

    if (set == null) {
      String add = "";

      if (!calculatedDeltaXneeded) {
        add = ". The label DELTAX is missing and " + "can not be calculated";
      }

      throw new JCAMPException("The label FIRSTX is missing" + add);
    }

    firstX = getDouble(set);

    set = getParameter("NPOINTS");

    if (set == null) {
      String add = "";

      if (!calculatedDeltaXneeded) {
        add = ". The label NPOINTS is missing and DELTAX" + "can not be calculated";
        throw new JCAMPException("The label FIRSTX is missing" + add);
      }

      logger.warn("The label NPOINTS is missing. Now its estimated");
      estimatedNPointsNeeded = true;
    }

    nPoints = getDouble(set);

    // Berechnung von deltaX;
    if (calculatedDeltaXneeded) {
      deltaX = (lastX - firstX) / (nPoints - 1);
    } else {
      double dummy = 0;

      if (!estimatedNPointsNeeded && (nPoints != 0)) {
        // einfach nochmals zur Kontrolle von deltaX. Eigentlich unnoetig !
        dummy = (lastX - firstX) / (nPoints - 1);

        if (Math.abs(dummy - deltaX) > DELTAX_DIFFERENCE_WARNING_VALUE) {
          logger.warn(
              "The calculated DELTAX="
                  + dummy
                  + " (original DELTAX="
                  + deltaX
                  + ") shows a difference above "
                  + DELTAX_DIFFERENCE_WARNING_VALUE);
        }
      }
    }

    set = getParameter("XFACTOR");

    if (set == null) {
      throw new JCAMPException("The label XFACTOR is missing");
    }

    xFactor = getDouble(set);

    set = getParameter("YFACTOR");

    if (set == null) {
      throw new JCAMPException("The label YFACTOR is missing");
    }

    yFactor = getDouble(set);

    // beginne Dekodierung
    set = getParameter("XYPAIRS");

    // if (set == null)
    // {
    // }
    //    if(dataType==XYPAIRS){
    //      end=set.getData().indexOf("\n",0);
    //      if (end==-1)throw new JCAMPException("Carriage return after \"=\" is not allowed");
    //      s1=set.getData().substring(0, end).trim();
    //    }
    //    else
    if (dataType == XYDATA_X_YY) {
      set = getParameter("XYDATA");

      //            if (set == null)
      //            {
      //            }
      end = set.getData().indexOf("\n", 0);

      if (end == -1) {
        throw new JCAMPException("Carriage return" + " after \"=\" is not allowed");
      }

      s1 = set.getData().substring(0, end).trim();
    }

    s1 = set.getData().substring(end + 1, set.getData().indexOf("\n", end + 1));

    // s1=s1.trim();
    // hier findet keine Unterscheidung zwischen AFFN (ungepackt) oder ASDF (gepackt) statt
    // Pseudo-digits or ASDF forms
    // ASCII digits          0 1 2 3 4 5 6 7 8 9
    // Positive SQZ digits   @ A B C D E F G H I
    // Negative SQZ digits     a b c d e f g h i
    // Positive DIF digits   % J K L M N O P Q R
    // Negative DIF digits     j k l m n o p q r
    // Positive DUP digits     S T U V W X Y Z s
    StringTokenizer isAFFN =
        new StringTokenizer(s1, "@ABCDEFGHIabcdefghi%JKLMNOPQRjklmnopqrSTUVWXYZs");

    try {
      s2 = isAFFN.nextToken();

      if (s1.equals(s2)) {
        // ist ein Token enthalten, so ist s1 ungleich s2
        // OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
        // nur AFFN !!!
        // OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
        // wieviele Datenpunkte sind es denn etwa ?
        //                StringTokenizer dataValue = new StringTokenizer(s1, " \t");
        // ruhig groS waehlen, da sie nachher eh geloescht werden.
        //            int dataPerLine=100;
        // Anzahl der Datenwerte ist NPOINTS/countTokens
        // dataPerLine=Math.max(dataValue.countTokens(), 100);
        //            yData= new Vector((int)nPoints, dataPerLine);
        //            xData= new Vector((int)nPoints, dataPerLine);
        xData = new LinkedList();
        yData = new LinkedList();

        begin = 0;
        begin = set.getData().indexOf("\n", begin);
        begin++;

        do {
          end = set.getData().indexOf("\n", begin);

          if (set.getData().indexOf(";", begin) != -1) {
            end = Math.min(end, set.getData().indexOf(";", begin));
          }

          if (end == -1) {
            break;
          }

          s1 = set.getData().substring(begin, end).trim();

          // dataLine
          // println("s1:"+parameterSaetze[1].substring(begin,end));
          addXYDATADataLine(s1);
          begin = end + 1;
        } while (true);

        sendDataToDoubleArray();

        return;
      } else {
        throw new JCAMPException("Compressed data in ASDF format is not supported ");
      }
    } catch (NoSuchElementException e) {
      logger.error(e.getMessage());
    }
  }