/**
 *
 */
package com.beem.project.beem.jingle;

import java.util.ArrayList;
import java.util.List;

import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.jingle.JingleManager;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
import org.jivesoftware.smackx.jingle.media.PayloadType;
import org.jivesoftware.smackx.jingle.nat.BasicTransportManager;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;

import android.util.Log;

/**
 * Beem Jingle Service, manage jingle call.
 * 
 * @author nikita
 */
public class JingleService {
	private static final String TAG = "JingleService";
	private JingleManager mJingleManager;
	private final List<JingleMediaManager> mMediaManagers;
	private JingleSession mIn;
	private JingleSession mOut;

	/**
	 * JingleService constructor.
	 * 
	 * @param xmppConnection
	 *            a valid XMPPConnection
	 */
	public JingleService(final XMPPConnection xmppConnection) {
		BasicTransportManager bt = new BasicTransportManager();
		// JingleTransportManager tm = new ICETransportManager();

		mMediaManagers = new ArrayList<JingleMediaManager>();
		mMediaManagers.add(new MicrophoneRTPManager(bt));
	}

	/**
	 * finish to construct the instance.
	 * 
	 * @param conn
	 *            the xmppConnection used with constructor
	 */
	public void initWhenConntected(XMPPConnection conn) {
		mJingleManager = new JingleManager(conn, mMediaManagers);
		mJingleManager.addJingleSessionRequestListener(new BeemJingleSessionRequestListener());
	}

	/**
	 * begin a jingle call.
	 * 
	 * @param receiver
	 *            the call receiver
	 */
	public void call(final String receiver) {
		try {
			mOut = mJingleManager.createOutgoingJingleSession(receiver);
			// TODO configure out avec addMediaSession et addNegociator
			mOut.addListener(new BeemJingleCallerSessionListener());
			mOut.startOutgoing();
		} catch (XMPPException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/*
	 * private void receiveData(String ip, int port) throws IOException { Socket
	 * s = null; try { s = new Socket(ip, port);
	 * System.out.println("Waiting data"); InputStream in = s.getInputStream();
	 * int a; while ((a = in.read()) != -1) { System.out.println("Received " +
	 * a); } System.out.println("End receiving data"); } finally { if (s !=
	 * null) s.close(); } }
	 */
	/**
	 * Listen on receiver session events.
	 * 
	 * @author nikita
	 */
	private class BeemJingleReceiverSessionListener implements JingleSessionListener {

		/**
		 * constructor.
		 */
		public BeemJingleReceiverSessionListener() {
			super();
			// TODO Auto-generated constructor stub
		}

		@Override
		public void sessionClosed(String reason, JingleSession jingleSession) {
			// System.out.println("Session " + jingleSession.getResponder() +
			// "closedd because " + reason);
		}

		@Override
		public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
			// TODO Auto-generated method stub
			// System.out.println("Session " + jingleSession.getResponder() +
			// " closed");

		}

		@Override
		public void sessionDeclined(String reason, JingleSession jingleSession) {
			Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason);
		}

		@Override
		public void sessionEstablished(PayloadType pt, TransportCandidate remoteCandidate,
				TransportCandidate localCandidate, JingleSession jingleSession) {
			// System.out.println("Session established");
			// System.out.println("Je recois sur " + remoteCandidate.getIp() +
			// ":" + remoteCandidate.getPort());
			// TODO choose the right RTPReceiver depending on the payload type
			// RTPReceiver rtpReceiver = new
			// RTPReceiver(remoteCandidate.getPort());
			Log.d(TAG, "Session " + jingleSession.getResponder() + "established");
		}

		@Override
		public void sessionMediaReceived(JingleSession jingleSession, String participant) {
			// System.out.println("Session Media received from " + participant);
		}

		@Override
		public void sessionRedirected(String redirection, JingleSession jingleSession) {
		}
	}

	/**
	 * Listen on caller session events.
	 * 
	 * @author nikita
	 */
	private class BeemJingleCallerSessionListener implements JingleSessionListener {

		private static final int SLP_DURATION = 20000;

		/**
		 * constructor.
		 */
		public BeemJingleCallerSessionListener() {
			super();
			// TODO Auto-generated constructor stub
		}

		@Override
		public void sessionClosed(final String reason, final JingleSession jingleSession) {
			// System.out.println("Session " + jingleSession.getResponder() +
			// "closed because " + reason);
		}

		@Override
		public void sessionClosedOnError(final XMPPException e, final JingleSession jingleSession) {
			// System.out.println("Session " + jingleSession.getResponder() +
			// " closed on error");

		}

		@Override
		public void sessionDeclined(final String reason, final JingleSession jingleSession) {
			// System.out.println("Session " + jingleSession.getResponder() +
			// "declined because " + reason);
			Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason);
		}

		@Override
		public void sessionEstablished(final PayloadType pt, final TransportCandidate remoteCandidate,
				final TransportCandidate localCandidate, final JingleSession jingleSession) {
			Log.d(TAG, "Session " + jingleSession.getResponder() + "established");
			// String name = localCandidate.getName();
			String ip = localCandidate.getIp();
			int port = localCandidate.getPort();
			// System.out.println("Session established waiting connection on " +
			// ip + ":" + port);

			RTPTransmitter transm = new PCMTransmitter(ip, port);

			transm.run();
			try {
				Thread.sleep(SLP_DURATION);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			transm.stop();
			// System.out.println("End of transfer");

		}

		@Override
		public void sessionMediaReceived(final JingleSession jingleSession, final String participant) {
			// TODO Auto-generated method stub
			System.out.println("Session Media received from " + participant);
		}

		@Override
		public void sessionRedirected(final String redirection, final JingleSession jingleSession) {
			// TODO Auto-generated method stub
		}
	}

	/**
	 * Listen for a Jingle session request.
	 * 
	 * @author nikita
	 */
	private class BeemJingleSessionRequestListener implements JingleSessionRequestListener {

		/**
		 * Constructor.
		 */
		public BeemJingleSessionRequestListener() {
			super();
		}

		@Override
		public void sessionRequested(JingleSessionRequest request) {
			System.out.println("Jingle Session request from " + request.getFrom());
			try {
				mIn = request.accept();
				mIn.addListener(new BeemJingleReceiverSessionListener());
				mIn.startIncoming();
			} catch (XMPPException e) {
				e.printStackTrace();
			}
		}
	}

}
