package org.wikiwebserver.util;

import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;

import com.sun.speech.freetts.audio.*;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class AudioPlayerStreamer implements AudioPlayer {
    
    private AudioFormat currentFormat = null;
    private AudioFileFormat.Type outputType;
    private ByteArrayOutputStream temp;
    private ByteArrayOutputStream out;


    /**
     * Constructs a FileAudioPlayer 
     *
     * @param out the OutputStream to direct audio data
     * @param type the type of audio output
     *
     */
    public AudioPlayerStreamer(ByteArrayOutputStream out, AudioFileFormat.Type type) {
        this.out = out;
        this.outputType = type;
        this.temp = new ByteArrayOutputStream();
    }

    /**
     * Sets the audio format for this player
     *
     * @param format the audio format
     *
     * @throws UnsupportedOperationException if the line cannot be opened with
     *     the given format
     */
    public synchronized void setAudioFormat(AudioFormat format) {
        currentFormat = format;
    }


    /**
     * Gets the audio format for this player
     *
     * @return format the audio format
     */
    public AudioFormat getAudioFormat() {
        return currentFormat;
    }


    /**
     * Pauses audio output
     */
    public void pause() {
    }

    /**
     * Resumes audio output
     */
    public synchronized void resume() {
    }
    


    /**
     * Cancels currently playing audio
     */
    public synchronized void cancel() {
    }

    /**
     * Prepares for another batch of output. Larger groups of output
     * (such as all output associated with a single FreeTTSSpeakable)
     * should be grouped between a reset/drain pair.
     */
    public synchronized void reset() {
    }


    /**
     * Starts the first sample timer
     */
    public void startFirstSampleTimer() {
    }

    /**
     * Closes this audio player
     */
    public synchronized void close() {
        try {
            byte[] data = temp.toByteArray();
            temp = null; // Free up for garbage collection
            
            ByteArrayInputStream in = new ByteArrayInputStream(data);
    
            int numFrames = data.length / currentFormat.getFrameSize();

            // Create input stream from raw audio data
            AudioInputStream ais = new AudioInputStream(in, currentFormat, numFrames);
               
            // Use the audio system to compress the audio stream
            AudioInputStream lowais = AudioSystem.getAudioInputStream(AudioFormat.Encoding.ULAW, ais);
            
            // Write the compressed audio stream to the byte array output stream
            AudioSystem.write(lowais, outputType, out);
            
        } catch (IOException ioe) {
        } catch (IllegalArgumentException iae) {
            iae.printStackTrace();
        }
    }


    /**
     * Returns the current volume.
     *
     * @return the current volume (between 0 and 1)
     */
    public float getVolume() {
        return 1.0f;
    }         

    /**
     * Sets the current volume.
     *
     * @param volume  the current volume (between 0 and 1)
     */
    public void setVolume(float volume) {
    }         




    /**
     *  Starts the output of a set of data. Audio data for a single
     *  utterance should be grouped between begin/end pairs.
     *
     * @param size the size of data between now and the end
     */
    public void begin(int size) {
    }

    /**
     *  Marks the end of a set of data. Audio data for a single 
     *  utterance should be groupd between begin/end pairs.
     *
     *  @return true if the audio was output properly, false if the
     *      output was cancelled or interrupted.
     *
     */
    public boolean  end() {
        return true;
    }


    /**
     * Waits for all queued audio to be played
     *
     * @return true if the audio played to completion, false if
     *   the audio was stopped
     */
    public boolean drain()  {
        return true;
    }

    /**
     * Gets the amount of played since the last mark
     *
     * @return the amount of audio in milliseconds
     */
    public synchronized long getTime()  {
        return -1L;
    }


    /**
     * Resets the audio clock
     */
    public synchronized void resetTime() {
    }
    

    
    /**
     * Writes the given bytes to the audio stream
     *
     * @param audioData audio data to write to the device
     *
     * @return <code>true</code> of the write completed successfully, 
     *          <code> false </code>if the write was cancelled.
     */
    public boolean write(byte[] audioData) {
        return write(audioData, 0, audioData.length);
    }
    
    /**
     * Writes the given bytes to the audio stream
     *
     * @param bytes audio data to write to the device
     * @param offset the offset into the buffer
     * @param size the size into the buffer
     *
     * @return <code>true</code> of the write completed successfully, 
     *          <code> false </code>if the write was cancelled.
     */
    public boolean write(byte[] bytes, int offset, int size) {
        temp.write(bytes, offset, size);
        return true;
    }


    /**
     * Returns the name of this audioplayer
     *
     * @return the name of the audio player
     */
    public String toString() {
        return "FileAudioPlayer";
    }



    /**
     * Shows metrics for this audio player
     */
    public void showMetrics() {
    }
}
