// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.

package net.avadeaux.klipspringer.codec.spi;

import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import javax.sound.sampled.*;
import net.avadeaux.klipspringer.codec.*;
import javax.sound.sampled.spi.AudioFileReader;

/** Base class for reading input file formats supported by Klipspringer. */
public class KlipspringerAudioFileReader extends AudioFileReader {
    private final DecoderAudioInputStream.DecoderFactory fact;

    KlipspringerAudioFileReader(DecoderAudioInputStream.DecoderFactory fact) {
        this.fact = fact;
    }

    private static String fileName(URL url) throws UnsupportedAudioFileException {
        if ("file".equalsIgnoreCase(url.getProtocol())) {
            String dir = url.getHost();
            return (dir == null ? "" : dir)+url.getFile();
        } else {
            throw new UnsupportedAudioFileException("Klipspringer SPI cannot read from stream, only file supported");
        }
    }

    private AudioFileFormat getAudioFileFormat(String file) throws UnsupportedAudioFileException {
        AudioFileFormat[] ffp = new AudioFileFormat[1];
        try (AudioDecoder decoder = fact.createAudioDecoder(file, new AudioDecoder.Target() {
                public void metadata(PcmFormat format, long totalFrames) {
                    ffp[0] = new AudioFileFormat(fact.type(file), format, totalFrames <= Integer.MAX_VALUE ? (int) totalFrames : AudioSystem.NOT_SPECIFIED);
                }
                public boolean write(ByteBuffer data) { return false; }
                public void close() { }
            }))
        {
            decoder.decodeMetadata();
        } catch (IOException ex) {
            throw new UnsupportedAudioFileException();
        }
        return ffp[0];
    }

    /** Decodes format of file. */
    public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
        return getAudioFileFormat(file.toString());
    }

    /** Throws {@link UnsupportedAudioFileException}, since stream decoding is not supported. */
    public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException {
        throw new UnsupportedAudioFileException("Klipspringer SPI cannot read from stream, only file supported");
    }

    /** Decodes format of file if given a <code>file://</code> URL, otherwise throws {@link
      * UnsupportedAudioFileException}
      */
    public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
        return getAudioFileFormat(fileName(url));
    }

    /** Decodes file. */
    public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
        return DecoderAudioInputStream.getInstance(file.toString(), fact);
    }

    /** Throws {@link UnsupportedAudioFileException}, since stream decoding is not supported. */
    public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException {
        throw new UnsupportedAudioFileException("Klipspringer SPI cannot read from stream, only file supported");
    }

    /** Decodes file if given a <code>file://</code> URL, otherwise throws {@link
      * UnsupportedAudioFileException}.
      */
    public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
        return DecoderAudioInputStream.getInstance(fileName(url), fact);
    }
}
