/*****************************************************************************
 *
 *                      AIRBIQUITY PROPRIETARY INFORMATION
 *
 *          The information contained herein is proprietary to Airbiquity
 *           and shall not be reproduced or disclosed in whole or in part
 *                    or used for any design or manufacture
 *              without direct written authorization from Airbiquity.
 *
 *            Copyright (c) 2012 by Airbiquity.  All rights reserved.
 *            
 *                   @author 
 *                   Jack Li
 *
 *****************************************************************************/
package com.airbiquity.mcs.ttcp;

import android.util.Log;

import com.airbiquity.mcs.common.IMCSConnectionAddress;
import com.airbiquity.mcs.common.IMCSMultiPointLayer;
import com.airbiquity.mcs.common.IMcsConListener;
import com.airbiquity.mcs.common.MCSException;
import com.airbiquity.mcs.common.McsLayer;
import com.airbiquity.mcs.common.McsLayerListener;

/**
 * TODO
 */
public class SendMessageModule implements IMcsConListener, McsLayerListener {
	
	private IMCSMultiPointLayer m_multiPointLayer;
	IMCSConnectionAddress m_myAddress;
	IMCSConnectionAddress m_remoteAddress;
	IMCSConnectionAddress m_remoteAddressAccept;
	McsLayer m_dataLayer;
	String m_name;
	byte[] m_buffer;
	IDataNotification m_notifiable;
	
	/**
	 * TODO
	 * @param name
	 * @param multi
	 * @param myAddress
	 * @param remoteAddress
	 * @param remoteAddressAccept
	 * @throws MCSException
	 */
	public SendMessageModule(String name, IMCSMultiPointLayer multi, IMCSConnectionAddress myAddress, IMCSConnectionAddress remoteAddress, IMCSConnectionAddress remoteAddressAccept) throws MCSException {
		m_multiPointLayer = multi;
		m_myAddress = myAddress;
		m_remoteAddress = remoteAddress;
		m_remoteAddressAccept = remoteAddressAccept;
		//m_multiPointLayer.registerNotification(this);
		m_multiPointLayer.addListener(this);
		m_buffer = new byte[4096];
		m_name = name;
	}
	/**
	 * TODO
	 * @param notifiable
	 */
	public void registerNotification(IDataNotification notifiable) {
		m_notifiable = notifiable;
	}
	/**
	 * TODO
	 * @throws MCSException
	 */
	public void openConnection() throws MCSException {
		Log.d("TAG", m_remoteAddress.toString());
		Log.d("TAG", m_myAddress.toString());
		m_dataLayer = m_multiPointLayer.createConnectionPoint(m_remoteAddress, m_myAddress);
		m_dataLayer.addListener(this);
		m_dataLayer.sendConnect();
		int current = 0;
		int sleepTime = 10; // ms
		int maxSleepTime = 5000;
		while(!m_dataLayer.isReady()) {
			try {
				current += sleepTime;
				if(current > maxSleepTime){
					throw new MCSException("Error connecting to remote address");
				}
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				// Log.e(TAG,"Exception : "+e.getMessage());
				e.printStackTrace();
			}
		}
	}
	/**
	 * TODO
	 * @param message
	 */
	public void sendMessage(String message) {
		byte[] buf = message.getBytes();
		sendMessage(buf);
	}
	/**
	 * TODO
	 * @param buffer
	 */
	public void sendMessage(byte[] buffer) {
		m_dataLayer.writeData(buffer, buffer.length);
	}
	/**
	 * TODO
	 * @param buffer
	 * @param size
	 */
	public void sendMessage(byte[] buffer, int size) {
		m_dataLayer.writeData(buffer, size);
	}

	public void newConnectionRequested(IMCSConnectionAddress fromAddress,
			IMCSConnectionAddress toAddress, byte[] payload) {
		if( fromAddress.isSubsetOf(m_remoteAddressAccept) && toAddress.isSameAs(m_myAddress) ) {
			try {
				m_dataLayer = m_multiPointLayer.createConnectionPoint(fromAddress, toAddress);
				
			//	m_dataLayer.registerNotification(this);
				m_dataLayer.addListener(this);
				// TODO: handle case with multiple connections
				// Above code replaces the last connection
			} catch (MCSException e) {
				//MCSLogger.log("SendMessageTest Exception", e.toString());
				Log.e("SendMessageTest Exception", e.toString());
				
			}
		}
	}

	public void onConnectionClosed(McsLayer connection,
			IMCSConnectionAddress fromAddress, IMCSConnectionAddress toAddress) {
		if(connection == m_dataLayer) {
			//m_dataLayer.unRegisterNotification(this);
			m_dataLayer.removeListener(this);
			m_dataLayer = null;
		}
	}

	public void onDataReceived() {
	    if( m_dataLayer == null || m_buffer == null ) {
	        return;
	    }
	    
		int size = m_dataLayer.readData(m_buffer, m_buffer.length);
		
		// Test code
		// String str = new String(m_buffer, 0, size);
		// MCSLogger.log("Received message in " + m_name, str);
		// Test code end
		
		if( m_notifiable != null ) {
			m_notifiable.onDataReceived(m_buffer, size);
		}
	}

	public void onConnectionClosed() {
		//m_dataLayer.unRegisterNotification(this);
		m_dataLayer.removeListener(this);
		m_dataLayer = null;
	}

	/**
	 * TODO
	 */
	public void closeConnection() {
		if (m_dataLayer != null) {
			//m_dataLayer.unRegisterNotification(this);
			m_dataLayer.removeListener(this);
			McsLayer temp = m_dataLayer;
			m_dataLayer = null;
			try {
				m_multiPointLayer.closeConnection(temp);
			} catch (MCSException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (m_buffer != null) {
			//mock MemPool free buffer, so that dvm will cause gc to buffer.
			m_buffer = null;
		}
	}
}
