/**
 *
 */
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();
	    }
	}
    }

}
