/** @return list of artwork images */
  public List<Artwork> getArtworkList() {
    List<Artwork> artworkList = new ArrayList<Artwork>(1);

    // Read Old Format
    if (getArtworkBinaryData() != null & getArtworkBinaryData().length > 0) {
      Artwork artwork = new Artwork();
      artwork.setMimeType(getArtworkMimeType());
      artwork.setBinaryData(getArtworkBinaryData());
      artworkList.add(artwork);
    }

    // New Format (Supports Multiple Images)
    List<TagField> metadataBlockPics = this.get(VorbisCommentFieldKey.METADATA_BLOCK_PICTURE);
    for (TagField tagField : metadataBlockPics) {

      try {
        byte[] imageBinaryData = Base64Coder.decode(((TagTextField) tagField).getContent());
        MetadataBlockDataPicture coverArt =
            new MetadataBlockDataPicture(ByteBuffer.wrap(imageBinaryData));
        Artwork artwork = Artwork.createArtworkFromMetadataBlockDataPicture(coverArt);
        artworkList.add(artwork);
      } catch (IOException ioe) {
        throw new RuntimeException(ioe);
      } catch (InvalidFrameException ife) {
        throw new RuntimeException(ife);
      }
    }
    return artworkList;
  }
  /**
   * Create MetadataBlockPicture field, this is the preferred way of storing artwork in
   * VorbisComment tag now but has to be base encoded to be stored in VorbisComment
   *
   * @return MetadataBlockDataPicture
   */
  private MetadataBlockDataPicture createMetadataBlockDataPicture(Artwork artwork)
      throws FieldDataInvalidException {
    if (artwork.isLinked()) {
      return new MetadataBlockDataPicture(
          Utils.getDefaultBytes(artwork.getImageUrl(), TextEncoding.CHARSET_ISO_8859_1),
          artwork.getPictureType(),
          MetadataBlockDataPicture.IMAGE_IS_URL,
          "",
          0,
          0,
          0,
          0);
    } else {
      BufferedImage image;
      try {
        image = artwork.getImage();
      } catch (IOException ioe) {
        throw new FieldDataInvalidException(
            "Unable to create MetadataBlockDataPicture from buffered:" + ioe.getMessage());
      }

      return new MetadataBlockDataPicture(
          artwork.getBinaryData(),
          artwork.getPictureType(),
          artwork.getMimeType(),
          artwork.getDescription(),
          image.getWidth(),
          image.getHeight(),
          0,
          0);
    }
  }
  /**
   * Nimmt die aktuell in <code>tags</code> vorhandenen Metatags, und befŸllt die Editorfelder
   * dementsprechend, dass diese bearbeitet werden kšnne.<br>
   * Hierbei ist das bearbeiten eines einzelnen {@link Tag}s als auch das bearbeiten von mehreren
   * mšglich.
   *
   * @see #editTag(Tag)
   * @see #editTags(ArrayList)
   */
  private void updateEditorControls() {
    watchComponentsForChange = false;

    /* Felder zurücksetzen: */
    editorChanged = false;
    ((EditorComboBoxModel) comTitle.getModel()).reset();
    ((EditorComboBoxModel) comArtist.getModel()).reset();
    ((EditorComboBoxModel) comAlbum.getModel()).reset();
    ((EditorComboBoxModel) comGenre.getModel()).reset();
    txtTracknumber.setText("");
    txtTotalTracks.setText("");
    txtDiscnumber.setText("");
    txtTotalDiscs.setText("");
    txtYear.setText("");
    imgArtwork.setArtwork(null);
    imgArtwork.setChanged(false);

    if (audioFiles == null || audioFiles.size() == 0) {
      setEditorEnabled(false);
    } else {
      setEditorEnabled(true);

      if (audioFiles.size() == 1) {
        // SingleFile-Editing
        AudioFile audioFile = audioFiles.get(0);
        Tag tag = audioFile.getTag();

        /* Felder aktualisieren: */
        comTitle.addItem(tag.getFirstTitle());
        comTitle.setSelectedIndex(comTitle.getItemCount() - 1);
        comArtist.addItem(tag.getFirstArtist());
        comArtist.setSelectedIndex(comArtist.getItemCount() - 1);
        comAlbum.addItem(tag.getFirstAlbum());
        comAlbum.setSelectedIndex(comAlbum.getItemCount() - 1);

        String[] numberBuffer = splitNumberData(tag.getFirstTrack());
        txtTracknumber.setText(numberBuffer[0]);
        txtTracknumber.setEnabled(true);
        txtTotalTracks.setText(numberBuffer[1]);
        numberBuffer = splitNumberData(tag.getFirst(TagFieldKey.DISC_NO));
        txtDiscnumber.setText(numberBuffer[0]);
        txtTotalDiscs.setText(numberBuffer[1]);

        txtYear.setText(tag.getFirstYear());

        EditorComboBoxModel model = (EditorComboBoxModel) comGenre.getModel();
        String genre = tag.getFirstGenre();
        model.addIfNotExists(genre);
        comGenre.setSelectedItem(genre);

        try {
          Artwork artwork = tag.getFirstArtwork();
          BufferedImage cover = null;
          if (artwork != null)
            cover = ImageIO.read(new ByteArrayInputStream(artwork.getBinaryData()));
          imgArtwork.setArtwork(cover);
          imgArtwork.setChanged(false);
        } catch (Exception e) {
          e.printStackTrace();
        }

      } else {
        /* MutliFile-Editing: */
        // ComboBoxes befŸllen:
        // Wenn mehrere Audiodateien gewŠhlt sind, ist es meistens auch der
        // Fall, dass beispielsweise die verschiedenen Files einen verschiedenen
        // Album-Tag haben. Damit der User nicht "von null" ein Album eingeben
        // muss, hat er die Mšglichkeit, zwischen den bereits vorhandenen Varianten
        // eine auszusuchen.
        EditorComboBoxModel model = null;

        String totalTracks = "-1";
        String discnumber = "-1";
        String totalDiscs = "-1";
        for (AudioFile audioFile : audioFiles) {
          Tag tag = audioFile.getTag();

          // Title:
          model = (EditorComboBoxModel) comTitle.getModel();
          model.addIfNotExists(tag.getFirstTitle());

          // Artists:
          model = (EditorComboBoxModel) comArtist.getModel();
          model.addIfNotExists(tag.getFirstArtist());

          // Albums:
          model = (EditorComboBoxModel) comAlbum.getModel();
          model.addIfNotExists(tag.getFirstAlbum());

          // Genre.
          model = (EditorComboBoxModel) comGenre.getModel();
          model.addIfNotExists(tag.getFirstGenre());

          // Total Tracks:
          String[] splitBuffer = splitNumberData(tag.getFirstTrack());
          if (totalTracks.equals("-1") || totalTracks.equals(splitBuffer[1])) {
            totalTracks = splitBuffer[1];
          } else {
            totalTracks = "";
          }

          // Discs:
          splitBuffer = splitNumberData(tag.getFirst(TagFieldKey.DISC_NO));
          if (discnumber.equals("-1") || discnumber.equals(splitBuffer[0])) {
            discnumber = splitBuffer[0];
          } else {
            discnumber = "";
          }

          // Total Discs:
          if (totalDiscs.equals("-1") || totalDiscs.equals(splitBuffer[1])) {
            totalDiscs = splitBuffer[1];
          } else {
            totalDiscs = "";
          }
        }

        txtTracknumber.setText("");
        txtTracknumber.setEnabled(false);
        txtTotalTracks.setText(totalTracks);
        txtDiscnumber.setText(discnumber);
        txtTotalDiscs.setText(totalDiscs);
      }
    }

    watchComponentsForChange = true;
  }
    /**
     * @param aSourceFile
     * @param aTargetFile
     * @return conflict reason
     */
    private String getConflictReason(File aSourceFile, File aTargetFile) {
      try {
        if (aSourceFile.isDirectory()) {
          return null;
        }

        long check = aSourceFile.lastModified() - aTargetFile.lastModified();
        if (check == 0) {
          return null;
        }

        check = aSourceFile.length() - aTargetFile.length();
        if (check != 0) {
          return "length=" + aSourceFile.length() + ":" + aTargetFile.length();
        }

        if (!compareAll("mp3", getFileExtn(aSourceFile), getFileExtn(aTargetFile))) {
          return null;
        }

        Mp3Tag sourceTag = null;
        Mp3Tag targetTag = null;
        try {
          sourceTag = ID3Util.readTag(aSourceFile);
          targetTag = ID3Util.readTag(aTargetFile);
        } catch (AppException error) {
          error.printStackTrace();
          return null;
        }

        if (!AppUtil.compare(sourceTag.language, targetTag.language)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.genre, targetTag.genre)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.album, targetTag.album)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.year, targetTag.year)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.composer, targetTag.composer)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.albumArtist, targetTag.albumArtist)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.artist, targetTag.artist)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.trackNbr, targetTag.trackNbr)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        if (!AppUtil.compare(sourceTag.title, targetTag.title)) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }

        Artwork sourceArtwork = sourceTag.artwork;
        Artwork targetArtwork = targetTag.artwork;

        if (sourceArtwork != null && targetArtwork != null) {
          if (sourceArtwork.getBinaryData().length != targetArtwork.getBinaryData().length) {
            return "id3lang=" + sourceTag.language + ":" + targetTag.language;
          }
        } else if (sourceArtwork != null || targetArtwork != null) {
          return "id3lang=" + sourceTag.language + ":" + targetTag.language;
        }
      } catch (Exception error) {
        System.err.println(aSourceFile + "##" + aTargetFile);
        error.printStackTrace();
      }

      return null;
    }