/**
   * Parse the tmp file for tag data and create associated song
   *
   * @param dfi
   * @return song created from tag data
   */
  public static Song parseFileForSong(DiskFileItem dfi) { // TODO Think about where to move this.
    File audioFile = new File(dfi.getStoreLocation().toString().replace(".tmp", ".mp3"));
    //	"."+dfi.getContentType().substring(dfi.getContentType().indexOf("/")+1)));

    if (!dfi.getStoreLocation().renameTo(audioFile)) {
      log.error(
          "rename failed - store location:" + dfi.getStoreLocation() + ", audio file:" + audioFile);
    }

    AudioFile f = null;
    try {
      f = AudioFileIO.read(audioFile);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    Tag tag = f.getTag();
    if (tag == null) {
      tag = f.getTagOrCreateAndSetDefault();
    }
    Song song = new Song();
    try {
      song.setArtist(tag.getFirst(FieldKey.ARTIST));
      song.setAlbum(tag.getFirst(FieldKey.ALBUM));
      song.setTitle(tag.getFirst(FieldKey.TITLE));
      song.setYear(tag.getFirst(FieldKey.YEAR));
      song.setTrack(tag.getFirst(FieldKey.TRACK));
      song.setFilename(dfi.getName());
    } catch (KeyNotFoundException knfe) {
      log.error("song key not found", knfe);
    }
    return song;
  }
  private boolean setAlbumArt(
      byte[] imageBytes,
      String mp3Filename,
      String mp3outputFilename,
      String username,
      String title,
      String detailsUrl) {
    try {
      AudioFile f = AudioFileIO.read(new File(mp3Filename));
      Tag tag = f.getTagOrCreateAndSetDefault();

      tag.setField(FieldKey.ALBUM, username + ": " + title + " via SoundCloud.com");
      tag.setField(FieldKey.ARTIST, username);
      tag.setField(FieldKey.TITLE, title);
      tag.setField(FieldKey.URL_OFFICIAL_RELEASE_SITE, detailsUrl);

      Artwork artwork = ArtworkFactory.getNew();
      artwork.setBinaryData(imageBytes);
      artwork.setMimeType("image/jpg");

      tag.addField(artwork);

      f.commit();

      return true;
    } catch (Throwable e) {
      return false;
    }
  }
  public void testWriteToRelativeMp3File() {
    File orig = new File("testdata", "testV1.mp3");
    if (!orig.isFile()) {
      System.err.println("Unable to test file - not available");
      return;
    }

    File testFile = null;
    Exception exceptionCaught = null;
    try {
      testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3");

      // Copy up a level coz we need it to be in same folder as working directory so can just
      // specify filename
      File outputFile = new File(testFile.getName());
      boolean result = copy(testFile, outputFile);
      assertTrue(result);

      // make Relative
      assertTrue(outputFile.exists());
      // Read File okay
      AudioFile af = AudioFileIO.read(outputFile);

      // Create tag and Change File
      af.getTagOrCreateAndSetDefault();
      af.getTag().setField(ArtworkFactory.createArtworkFromFile(new File("testdata/coverart.jpg")));
      af.commit();

    } catch (Exception e) {
      e.printStackTrace();
      exceptionCaught = e;
    }

    assertNull(exceptionCaught);
  }
  /**
   * Update the GridFSDBFile in the associated DB with the key/values in updateKeys
   *
   * @param updateKeys Map of new tag data
   * @param file GridFSDBFile to update with tag data
   * @param db
   * @param songId ID of Song to update with tag data
   * @return
   */
  public static boolean updateFile(
      Map<String, String> updateKeys,
      GridFSDBFile file,
      DB db,
      ObjectId songId) { // TODO updateKeys?
    File audioFile = null;
    try {
      audioFile = File.createTempFile("tmp", ".mp3");
    } catch (IOException e) {
      log.error("tmp file not created", e);
    }

    audioFile.deleteOnExit();
    AudioFile f = null;
    ObjectId id = (ObjectId) file.getId();
    ObjectId oid = null;
    try {
      file.writeTo(audioFile);
      f = AudioFileIO.read(audioFile);
      Tag tag = f.getTagOrCreateAndSetDefault();
      DBObject q = new BasicDBObject("_id", songId);
      DBObject o = new BasicDBObject("$set", new BasicDBObject(updateKeys));

      if (updateKeys.get("artist") != null) {
        tag.setField(FieldKey.ARTIST, updateKeys.get("artist"));
      }
      if (updateKeys.get("album") != null) {
        tag.setField(FieldKey.ALBUM, updateKeys.get("album"));
      }
      if (updateKeys.get("title") != null) {
        tag.setField(FieldKey.TITLE, updateKeys.get("title"));
      }
      if (updateKeys.get("track") != null) {
        tag.setField(FieldKey.TRACK, updateKeys.get("track"));
      }
      if (updateKeys.get("year") != null) {
        tag.setField(FieldKey.YEAR, updateKeys.get("year"));
      }
      AudioFileIO.write(f);
      GridFS myFS = new GridFS(db);
      myFS.remove(id);
      GridFSInputFile inputFile =
          putSongFileInDB(f.getFile(), db, file.getContentType(), file.getFilename(), id);
      oid = (ObjectId) inputFile.getId();
      if (oid.equals(id)) {
        db.getCollection("songs").update(q, o);
      }
    } catch (KeyNotFoundException knfe) {
      log.error("key not found", knfe);
    } catch (FieldDataInvalidException fdie) {
      log.error("tried to set field with invalid value", fdie);
    } catch (Exception e) {
      log.error("error reading/writing file", e);
    }
    return (oid.equals(id));
  }
  /**
   * This will write a custom ID3 tag (TXXX). This works only with MP3 files (Flac with ID3-Tag not
   * tested).
   *
   * @param description The description of the custom tag i.e. "catalognr" There can only be one
   *     custom TXXX tag with that description in one MP3 file
   * @param text The actual text to be written into the new tag field
   * @return True if the tag has been properly written, false otherwise
   */
  public static boolean setCustomTag(AudioFile audioFile, String description, String text)
      throws IOException {
    FrameBodyTXXX txxxBody = new FrameBodyTXXX();
    txxxBody.setDescription(description);
    txxxBody.setText(text);

    // Get the tag from the audio file
    // If there is no ID3Tag create an ID3v2.3 tag
    Tag tag = audioFile.getTagOrCreateAndSetDefault();
    if (tag instanceof AbstractID3Tag) {
      // If there is only a ID3v1 tag, copy data into new ID3v2.3 tag
      if (!(tag instanceof ID3v23Tag || tag instanceof ID3v24Tag)) {
        Tag newTagV23 = null;
        if (tag instanceof ID3v1Tag) {
          newTagV23 =
              new ID3v23Tag((ID3v1Tag) audioFile.getTag()); // Copy old tag data
        }
        if (tag instanceof ID3v22Tag) {
          newTagV23 =
              new ID3v23Tag((ID3v22Tag) audioFile.getTag()); // Copy old tag data
        }
        audioFile.setTag(newTagV23);
        tag = newTagV23;
      }

      AbstractID3v2Frame frame = null;
      if (tag instanceof ID3v23Tag) {
        if (((ID3v23Tag) audioFile.getTag()).getInvalidFrames() > 0) {
          throw new IOException("read some invalid frames!");
        }
        frame = new ID3v23Frame("TXXX");
      } else if (tag instanceof ID3v24Tag) {
        if (((ID3v24Tag) audioFile.getTag()).getInvalidFrames() > 0) {
          throw new IOException("read some invalid frames!");
        }
        frame = new ID3v24Frame("TXXX");
      }

      frame.setBody(txxxBody);

      try {
        tag.setField(frame);
      } catch (FieldDataInvalidException e) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, e);
        return false;
      }
    } else if (tag instanceof FlacTag) {
      try {
        ((FlacTag) tag).setField(description, text);
      } catch (KeyNotFoundException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        return false;
      } catch (FieldDataInvalidException ex) {
        return false;
      }
    } else if (tag instanceof Mp4Tag) {
      // TagField field = new Mp4TagTextField("----:com.apple.iTunes:"+description, text);
      TagField field;
      field =
          new Mp4TagReverseDnsField(
              Mp4TagReverseDnsField.IDENTIFIER + ":" + "com.apple.iTunes" + ":" + description,
              "com.apple.iTunes",
              description,
              text);
      // TagField field = new Mp4TagTextField(description, text);
      try {
        tag.setField(field);
      } catch (FieldDataInvalidException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        return false;
      }
    } else if (tag instanceof VorbisCommentTag) {
      try {
        ((VorbisCommentTag) tag).setField(description, text);
      } catch (KeyNotFoundException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        return false;
      } catch (FieldDataInvalidException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        return false;
      }
    } else {
      // tag not implented
      Logger.getLogger(TrackAnalyzer.class.getName())
          .log(
              Level.WARNING,
              "couldn't write key information for "
                  + audioFile.getFile().getName()
                  + " to tag, because this format is not supported.");
      return false;
    }

    // write changes in tag to file
    try {
      audioFile.commit();
    } catch (CannotWriteException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }