/**
 * 
 */
package jp.ac.naka.ec.media;

import java.awt.Component;
import java.awt.Frame;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import javax.media.MediaException;
import javax.media.NoDataSinkException;
import javax.media.NotRealizedError;
import javax.media.format.AudioFormat;
import javax.sdp.Connection;
import javax.sdp.Media;
import javax.sdp.MediaDescription;
import javax.sdp.SdpConstants;
import javax.sdp.SdpException;
import javax.sdp.SessionDescription;

import jp.ac.naka.ec.entity.Entity;

/**
 * ラッパー
 * 
 * @author 粕谷
 * 
 */
public class AudioPlayer {

	// デフォルトポート
	protected int srcPort = 22224;

	// Payloadの最大数
	protected int limit = 3;
	private AudioReceiver receiver;
	private AudioTransmitter transmiter;
	protected List<Integer> availableAudioFormats = new ArrayList<Integer>();

	protected int[] receivableJmfAudioFormats = new int[] {
	// sdp format // corresponding JMF Format
			SdpConstants.G723, // javax.media.format.AudioFormat.G723_RTP
			SdpConstants.GSM, // javax.media.format.AudioFormat.GSM_RTP;
			SdpConstants.PCMU, // javax.media.format.AudioFormat.ULAW_RTP;
			SdpConstants.DVI4_8000, // javax.media.format.AudioFormat.DVI_RTP;
			SdpConstants.DVI4_16000, // javax.media.format.AudioFormat.DVI_RTP;
			SdpConstants.PCMA, // javax.media.format.AudioFormat.ALAW;
			SdpConstants.G728 // , //

	};

	public AudioPlayer() {
		init();
	}

	public AudioPlayer(int port) {
		this();
		srcPort = port;
	}

	private void init() {
		// ここで設定ファイルから選べるようにしよう
		Arrays.sort(receivableJmfAudioFormats);
		for (int format : receivableJmfAudioFormats) {
			availableAudioFormats.add(format);
		}
	}

	public SessionDescription getRequestSessionDescription(Entity source)
			throws UnknownHostException, SdpException {
		return getRequestSessionDescription(0, source.getName(), "s");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jp.ac.naka.ec.media.MediaPlayer#getRequestSessionDescription(int,
	 *      java.lang.String, java.lang.String)
	 */
	public SessionDescription getRequestSessionDescription(int version,
			String userName, String sessionName) throws UnknownHostException,
			SdpException {
		InetAddress addr = InetAddress.getLocalHost();
		List<Integer> video = null;

		SessionDescription sdp = SDPGenerator.getRequestSessionDescription(0,
				"media_sender", "-", addr.getHostAddress(),
				availableAudioFormats, srcPort, video, 0);
		return sdp;
	}

	public SessionDescription getResponseSessionDescription(String user,
			int port, SessionDescription sdp) throws UnknownHostException,
			SdpException {
		SessionDescription ret = SDPGenerator.getResponseSessionDescription(
				user, port, sdp);
		return ret;
	}

	/**
	 * ファイルからSDPのStringを生成
	 * 
	 * @param sdp_file
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static String getSessionDescriptionString(String sdp_file)
			throws FileNotFoundException, IOException {
		FileReader fr = new FileReader(sdp_file);
		BufferedReader br = new BufferedReader(fr);
		StringBuilder builder = new StringBuilder();
		int i = 0;
		while ((i = br.read()) != -1) {
			char c = (char) i;
			builder.append(c);
		}
		return builder.toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.iobb.ibaraki.media.MediaPlayer#addAvailableFormat(int)
	 */
	public void addAvailableFormat(int payload) {
		availableAudioFormats.add(payload);
	}

	/**
	 * RTPオーディオストリームの受信
	 * 
	 * @param sdp_string
	 * @throws SdpException
	 */
	public void receiveMediaStream(SessionDescription sdp)
			throws MediaException, SdpException {
		if (receiver == null) {
			receiver = new AudioReceiver();
		}
		receiver.receiveMedia(sdp);
	}

	/**
	 * RTPオーディオストリームの受信
	 * 
	 * @param sdp_string
	 * @throws SdpException
	 */
	public void receiveMediaStream(int port) throws MediaException,
			SdpException {
		if (receiver == null) {
			receiver = new AudioReceiver();
		}
		receiver.receiveMedia(port);
	}

	/**
	 * キャプチャで取得した音声のRTPによる送信。
	 * 
	 * @param sdp_string
	 * @throws MediaException
	 */

	public void sendMediaStream(String path, int port) throws MediaException {
		if (transmiter == null) {
			transmiter = new AudioTransmitter(path, port);
		}

	}

	/**
	 * キャプチャで取得した音声のRTPによる送信。
	 * 
	 * @param sdp_string
	 * @throws MediaException
	 * @throws IOException
	 * @throws SdpException
	 */
	public boolean sendMediaStream(SessionDescription sdp)
			throws MediaException, IOException, SdpException {
		return sendMediaStream(null, sdp);
	}

	public boolean sendMediaStream(String path, SessionDescription sdp)
			throws MediaException, IOException, SdpException {
		Connection c = sdp.getConnection();
		InetAddress addr = InetAddress.getByName(c.getAddress());
		Vector<MediaDescription> mds = sdp.getMediaDescriptions(true);
		AudioFormat format = null;
		int port = srcPort;
		for (MediaDescription md : mds) {
			Media media = md.getMedia();
			port = media.getMediaPort();
		}
		sdp = SDPGenerator.getResponseSessionDescription("-", port, sdp);
		mds = sdp.getMediaDescriptions(true);
		for (MediaDescription md : mds) {
			Media media = md.getMedia();
			Vector formats = media.getMediaFormats(true);

			port = media.getMediaPort();
			// 一番目のフォーマットを使う
			int payload = Integer.parseInt((String) formats.get(0));

			format = (AudioFormat) SDPGenerator
					.findCorrespondingFormat(payload);
			if (format == null) {
				throw new NullPointerException("Payload type " + payload
						+ " is not available");
			}
		}
		if (format == null)
			return false;
		transmiter = new AudioTransmitter(path, addr.getHostAddress(), port,
				format);
		transmiter.play();
		return true;
	}

	/**
	 * 音声ファイルからの音声のRTPによる送信。
	 * 
	 * @param sdp_String
	 * @param path
	 * @throws MediaException
	 */
	public void sendMediaStream(String dest_url, int port, String media)
			throws MediaException {
		transmiter = new AudioTransmitter(media, dest_url, port);
	}

	/**
	 * オーディオの受信を止める。
	 * 
	 */
	public boolean stopReceivingMediaStream() {
		if (receiver != null) {
			receiver.stop();
			return true;
		}
		return false;
	}

	/**
	 * オーディオの送信をやめる。
	 * 
	 */
	public boolean stopSendingMediaStream() {
		if (transmiter != null) {
			transmiter.close();
			transmiter = null;
			return true;
		}
		return false;
	}

	public boolean isPlaying() {
		if (receiver != null)
			return receiver.isPlaying();
		else if (transmiter != null)
			return transmiter.isPlaying();
		else
			return false;
	}

	public Component getTransmitterController() {
		return transmiter.getControlPanelComponent();
	}

	public Component getReceiverController() {
		return receiver.getControlPanelComponent();
	}

	public boolean isSending() {
		return transmiter.isPlaying();
	}

	public void setPort(int port) {
		srcPort = port;
	}

	public void store(String path) throws NoDataSinkException,
			NotRealizedError, SecurityException, IOException {
		receiver.store(path);
	}

	public static void main(String[] args) {
		AudioPlayer receiver = null;
		receiver = new AudioPlayer();

		try {
			InetAddress addr = InetAddress.getLocalHost();
			SessionDescription sdp = receiver.getRequestSessionDescription(0,
					"hoge", "-");
			// receiver.sendMediaStream(addr.getHostAddress(),
			// AudioPlayer.srcPort, null);
			receiver.receiveMediaStream(receiver.getResponseSessionDescription(
					"hoge", 5060, sdp));
			Frame frame = new Frame("test");
			frame.pack();
			frame.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
