package nxm.audio.prim;

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

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

import nxm.audio.lib.DataReader;
import nxm.audio.lib.hwplayer;
import nxm.sys.lib.MidasException;
import nxm.sys.lib.Primitive;

/**
THIS IS A WORK IN PROGRESS. DO NOT CHECK IN YET!!!!!
  Streams data to a hwplayer device.

  Currently, accepts linear 16-bit or mulaw formatted input and
  outputs to the audio driver.

  @author Lisa Tursky
  @see <a href="../exp/sinkhwplayer.exp">Explain</a>
  @see <a href="sinkhwplayer.java">Source</a>

 */
public class sinkhwplayer extends Primitive {

  private SourceDataLine audioLine;
  private AudioInputStream audioInputStream;
  private DataReader dataReader;
  private hwplayer player;
  private byte[] buf = new byte[65536];
  private boolean fileBased = false;

  /** default constructor */
  public sinkhwplayer () {}

  public int open() {
    String fileName = MA.getS("IN");
    String host = MA.getS("HOST","");
    int port = MA.getL("PORT",0);

    //INITIALIZE PLAYER
    player = new  hwplayer();
    player.open();
    audioLine = player.addChannel(0);

    //OPEN AUDIO FROM FILE
    if (!fileName.equals("")) {
      File audioFile = new File(fileName);
      fileBased = true;
      System.out.println("File exists? " + audioFile.exists());
      try {
        audioInputStream = AudioSystem.getAudioInputStream(audioFile);
      }
      catch (UnsupportedAudioFileException uae) {
        M.warning("Unsupported Audio File " + fileName);
      }
      catch (IOException ioe) {
        M.warning("IOException occurred: cannot open file " + fileName);
      }
    }
    else if (!host.equals("") && port > 0) {
      // OPEN AUDIO FROM MULTICAST STREAM
      dataReader = new DataReader(0, build_mu_decode_table(), 1, audioLine);
      dataReader.open(host,port);
    }

    return NORMAL;
  }

  public int process() {
    int bytesRead = 0;
    try {
      if (fileBased) {
        System.out.println("In here");
        bytesRead = audioInputStream.read(buf);
        while(bytesRead > 0) {
          player.play(player.getSourceDataLine(0), buf, bytesRead);
          bytesRead = audioInputStream.read(buf);
        }
      } else {
        dataReader.start();
      }
    }
    catch (IOException e) {
      throw new MidasException("Error during write", e);
      // This line discards any nested exception and makes debugging difficult.
      // M.error("Error during write: "+e);
    }
    player.close(0);

    return FINISH;
  }

  public int close() {
    try {
      if (audioInputStream != null) audioInputStream.close();
      if (dataReader != null) dataReader.shutdown();
    }
    catch (IOException ioe) {
      M.warning("Error closing audio stream");
    }

    return NORMAL;
  }

  private short[] build_mu_decode_table() {
    short[] convbuf = new short[256];
    for (int i=0; i<256; i++) {
      int j = i-128;
      int x = j^127;
      int S = 1-(2*((x&128)/128));
      int L = (x&112)/16;
      int V = x&15;
      convbuf[i] = (short) Math.round(((S*(Math.pow(2,L)*(2*V+33)-33)*32767.0) / 8031.0));
    }
    return convbuf;
  }
}
