package com.limegroup.gnutella.hashing;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.flac.FlacStreamReader;
import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockHeader;
import org.limewire.io.IOUtils;

/**
 * Locates the beginning and end of the audio portion of a FLAC file. This 
 * checks for ID3v2.x tags, and FLAC Headers at the begining of the file. 
 * Per FLAC spec, no tags are ever located at the end of the file so we 
 * assume EOF is end-of-audio. 
 */
class FLACNonMetaDataHasher extends NonMetaDataHasher {

    private final File file;
    
    FLACNonMetaDataHasher(File file) {
        this.file = file;
    }

    /**
     * Returns the start frame of this FLAC file. The FLAC audio 
     * stream may be preceded by an ID3 tag and a series of MetaData
     * Block Headers including an OGG_Comment header. This returns the
     * position of the first frame within the FLAC_Audio stream.
     */
    @Override
    public long getStartPosition() throws IOException {
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(file, "r");
            FlacStreamReader flacStream = new FlacStreamReader(raf);
            try {
                // attempt to locate the start of the FLAC file. ID3 tags
                // or other tags may be added before the FLAC Headers
                flacStream.findStream();
            } catch(CannotReadException e) {
                throw new IOException(e);
            }
            
            boolean isEndOfHeader = false;
            while(!isEndOfHeader) {
                MetadataBlockHeader mbh;
                try {
                    mbh = MetadataBlockHeader.readHeader(raf);
                } catch (CannotReadException e) {
                    throw new IOException(e);
                }
                
                raf.seek(raf.getFilePointer() + mbh.getDataLength());
    
                isEndOfHeader = mbh.isLastBlock();
            }
            return raf.getFilePointer();
        } finally {
            IOUtils.close(raf);
        }
    }

    /**
     * Returns the position of the end of the last frame of audio in this file. For
     * FLAC files this is equal to EOF.
     */
    @Override
    public long getEndPosition() throws IOException {
        return file.length();
    }
}
