/*
 * HA_ClientControlObject.cpp
 *
 */
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "header.h"
#include "HA_port.h"
#include "HA_log.h"
#include "HA_ClientControlObject.h"
#include "socketutil.h"
#include "HarkData.h"
#ifdef ENABLE_JNI_FOR_ANDROID
#include "HA_java.h"
#endif

namespace HARKAndroid {

ClientControlObject::ClientControlObject() : valid(false),
											Stopped(true)
{
	init();
}

ClientControlObject::~ClientControlObject()
{
	SetStop();
}

int ClientControlObject::init()
{
	int ret;

	ret = ::pthread_mutex_init(&Stop_mutex, NULL);
	if (ret != 0) {
		return(ret);
	}

	ret = ::pthread_mutex_init(&Start_Stop_mutex, NULL);
	if (ret != 0) {
		return(ret);
	}

	valid = true;

	return(0);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::Create(JNIEnv *env, jobject thiz)
#else
int ClientControlObject::Create()
#endif // ENABLE_JNI_FOR_ANDROID
{
	int ret = 0;

	return(ret);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::Start(JNIEnv *env, jobject thiz)
#else
int ClientControlObject::Start()
#endif // ENABLE_JNI_FOR_ANDROID
{
	lockobject lock(&Start_Stop_mutex);

	ResetStop();

	return(0);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::Stop(JNIEnv *env, jobject thiz)
#else
int ClientControlObject::Stop()
#endif // ENABLE_JNI_FOR_ANDROID
{
	lockobject lock(&Start_Stop_mutex);

	SetStop();

	return(0);
}

int ClientControlObject::ConnectPortA()
{
	int PortA_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_A);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortA_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortA_fd == -1) {
		LOGE("PortA socket error");
		return(-1);
	}

	// connect
	if (::connect(PortA_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortA connect error");
		close(PortA_fd);
		return(-1);
	}
	LOGD("connect PortA success");

	return(PortA_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortA(const int PortA_fd, jdouble *array) const
#else
int ClientControlObject::RecvFromPortA(const int PortA_fd, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint channel, length, advance;
#else
	int channel, length, advance;
#endif
	return this->RecvFromPortA(PortA_fd, &channel, &length, &advance, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortA(const int PortA_fd, jint *channel, jint *length, jint *advance, jdouble *mic_acoustics) const
#else
int ClientControlObject::RecvFromPortA(const int PortA_fd, int *channel, int *length, int *advance, float *mic_acoustics) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;

#ifdef ENABLE_JNI_FOR_ANDROID
	*channel = static_cast<jint>(0);
	*length  = static_cast<jint>(0);
	*advance = static_cast<jint>(0);
#else
	*channel = 0;
	*length  = 0;
	*advance = 0;
#endif // ENABLE_JNI_FOR_ANDROID
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortA_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			return(1);
		}
		else{
			LOGE("PortA recv ERROR");
			return(-1);
		}
	}
	else{
		// OK
		if(hdr.type != PACKET_MIC_WAVE){
			LOGE("FFT invalid header %d", hdr.type);
			return(-1);
		}
	}

	::HDH_MicData mic;
	readbyte = ::readsock(PortA_fd, reinterpret_cast<void *>(&mic), sizeof(mic), NULL, NULL);
	if(readbyte != sizeof(mic)){
		return(-1);
	}
	//else {
	//	if (mic.data_bytes != sizeof(data))	{
	//		LOGE("Wav invalid micdata.databytes %d", mic.data_bytes);
	//		return(-1);
	//	}
	//}

	float data[mic.length * mic.nch]; // 512 * 8

	readbyte = ::readsock(PortA_fd, reinterpret_cast<void *>(data), sizeof(data), NULL, NULL);
	if(readbyte != sizeof(data)){
		return(-1);
	}

	for(int i = 0; i < NELEM(data); i++){
#ifdef ENABLE_JNI_FOR_ANDROID
		*(mic_acoustics + i) = static_cast<jdouble>(data[i]);
#else
		*(mic_acoustics + i) = data[i];
#endif // ENABLE_JNI_FOR_ANDROID
	}

#ifdef ENABLE_JNI_FOR_ANDROID
	*channel = static_cast<jint>(mic.nch);
	*length  = static_cast<jint>(mic.length);
    *advance = static_cast<jint>(hdr.advance);
#else
	*channel = mic.nch;
	*length  = mic.length;
    *advance = hdr.advance;
#endif // ENABLE_JNI_FOR_ANDROID
	//LOGD("recv float %f", data[0]);

	return(0);
}

int ClientControlObject::ClosePortA(const int PortA_fd)
{
	::close(PortA_fd);
	return(0);
}

int ClientControlObject::ConnectPortB()
{
	int PortB_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_B);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortB_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortB_fd == -1) {
		LOGE("PortB socket error");
		return(-1);
	}

	// connect
	if (::connect(PortB_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortB connect error");
		close(PortB_fd);
		return(-1);
	}
	LOGD("connect PortB success");

	return(PortB_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortB(const int PortB_fd, jdouble *array) const
#else
int ClientControlObject::RecvFromPortB(const int PortB_fd, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint channel, length, advance, fft_length;
#else
	int channel, length, advance, fft_length;
#endif
	return this->RecvFromPortB(PortB_fd, &channel, &length, &advance, &fft_length, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortB(const int PortB_fd, jint *channel, jint *length, jint *advance, jint *fft_length, jdouble *mic_spectra) const
#else
int ClientControlObject::RecvFromPortB(const int PortB_fd, int *channel, int *length, int *advance, int *fft_length, float *mic_spectra) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;

#ifdef ENABLE_JNI_FOR_ANDROID
	*channel    = static_cast<jint>(0);
	*length     = static_cast<jint>(0);
	*advance    = static_cast<jint>(0);
	*fft_length = static_cast<jint>(0);
#else
	*channel    = 0;
	*length     = 0;
	*advance    = 0;
	*fft_length = 0;
#endif // ENABLE_JNI_FOR_ANDROID
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortB_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			return(1);
		}
		else{
			LOGE("PortB recv ERROR");
			return(-1);
		}
	}
	else{
		// read OK
		if(hdr.type != PACKET_MIC_FFT){
			LOGE("FFT invalid header %d", hdr.type);
			return(-1);
		}
	}

	::HDH_MicData mic;
	readbyte = ::readsock(PortB_fd, reinterpret_cast<void *>(&mic), sizeof(mic), NULL, NULL);
	if(readbyte != sizeof(mic)){
		return(-1);
	}
	//else {
	//	if (mic.data_bytes != sizeof(data)) {
	//		LOGE("FFT invalid micdata.databytes %d", mic.data_bytes);
	//		return(-1);
	//	}
	//}

	float data[((mic.length / 2) + 1) * 2 * mic.nch]; // ((512 / 2) + 1) * 2 * 8 // sizeof(complex) = sizeof(float * 2)

	readbyte = ::readsock(PortB_fd, reinterpret_cast<void *>(data), sizeof(data), NULL, NULL);
	if(readbyte != sizeof(data)){
		return(-1);
	}

	for(int i = 0; i < NELEM(data); i++){
#ifdef ENABLE_JNI_FOR_ANDROID
		*(mic_spectra + i) = static_cast<jdouble>(data[i]);
#else
		*(mic_spectra + i) = data[i];
#endif // ENABLE_JNI_FOR_ANDROID
	}

#ifdef ENABLE_JNI_FOR_ANDROID
	*channel     = static_cast<jint>(mic.nch);
	*length      = static_cast<jint>(mic.length);
    *advance     = static_cast<jint>(hdr.advance);
	*fft_length  = static_cast<jint>((mic.length / 2) + 1);
#else
	*channel     = mic.nch;
	*length      = mic.length;
    *advance     = hdr.advance;
	*fft_length  = (mic.length / 2) + 1;
#endif // ENABLE_JNI_FOR_ANDROID
	//LOGD("recv float %f", data[0]);

	return(0);
}

int ClientControlObject::ClosePortB(const int PortB_fd)
{
	::close(PortB_fd);
	return(0);
}


int ClientControlObject::ConnectPortC()
{
	int PortC_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_C);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortC_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortC_fd == -1) {
		LOGE("PortC socket error");
		return(-1);
	}

	// connect
	if (::connect(PortC_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortC connect error");
		close(PortC_fd);
		return(-1);
	}
	LOGD("connect PortC success");

	return(PortC_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortC(const int PortC_fd, jint *arraynum, jdouble *array) const
#else
int ClientControlObject::RecvFromPortC(const int PortC_fd, int *arraynum, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint source_ids[ARY_NUM_SRC];
#else
	int source_ids[ARY_NUM_SRC];
#endif
	return this->RecvFromPortC(PortC_fd, arraynum, source_ids, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortC(const int PortC_fd, jint *source_count, jint *source_ids, jdouble *source_coordinates) const
#else
int ClientControlObject::RecvFromPortC(const int PortC_fd, int *source_count, int *source_ids, float *source_coordinates) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortC_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			*source_count = 0;
			return(1);
		}
		else{
			LOGE("PortC recv ERROR");
			*source_count = 0;
			return(-1);
		}
	}
	else{
		// OK
		if(hdr.type != PACKET_SRC_INFO){
			LOGE("localizeMusic invalid header %d", hdr.type);
			*source_count = 0;
			return(-1);
		}
	}

	int data_num;
	readbyte = ::readsock(PortC_fd, reinterpret_cast<void *>(&data_num), sizeof(data_num), NULL, NULL);
	if (readbyte != sizeof(data_num)) {
		*source_count = 0;
		return(-1);
	}

	// 2013.04.02 K.Takagi
	// 上位から配列要素数を取得し、取得上限をチェック
	//source_count[0] = data_num;

	if(data_num > 0){
		//int ct = 0;
		//for(int i = 0; i < data_num; i++) {
		//	readbyte = ::readsock(PortC_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
		//	if(readbyte != sizeof(srcinfo)){
		//		LOGE("localizeMusic  %d", hdr.type);
		//		return(-1);
		//	}
		//	if(source_count[0] > ct){
		//		array[ct++] = srcinfo.x[0];
		//		array[ct++] = srcinfo.x[1];
		//	}
		//}
		int array_num = source_count[0] >> 1;
		if(array_num < data_num){
			LOGE("Array size is insufficient. recv = %d[sources], array = %d[sources]", data_num, array_num);
			*source_count = 0;
			return(-2);
		}
		else{
			HDH_SrcInfo srcinfo;
			int offset_src = 0;
			for(int i = 0; i < data_num; i++){
				readbyte = ::readsock(PortC_fd, reinterpret_cast<void *>(&srcinfo), sizeof(HDH_SrcInfo), NULL, NULL);
				if(readbyte != sizeof(srcinfo)){
					LOGE("localizeMusic  %d", hdr.type);
					*source_count = 0;
					return(-1);
				}
				*(source_ids + i) = srcinfo.src_id;
				source_coordinates[offset_src++] = srcinfo.x[0];
				source_coordinates[offset_src++] = srcinfo.x[1];
			}
		}
	}
	
//	if(source_count[0] > data_num){
		*source_count = data_num;
//	}
	//LOGD("recv float %f", data[0]);
	return(0);
}

int ClientControlObject::ClosePortC(const int PortC_fd)
{
	::close(PortC_fd);
	return(0);
}

int ClientControlObject::ConnectPortD()
{
	int PortD_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_D);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortD_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortD_fd == -1) {
		LOGE("PortD socket error");
		return(-1);
	}

	// connect
	if (::connect(PortD_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortD connect error");
		close(PortD_fd);
		return(-1);
	}
	LOGD("connect PortD success");

	return(PortD_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortD(const int PortD_fd, jdouble *array) const
#else
int ClientControlObject::RecvFromPortD(const int PortD_fd, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint    source_count;
	jint    fft_length;
	jint    source_ids[ARY_NUM_SRC];
	jdouble source_coordinates[ARY_NUM_SRC];
#else
	int   source_count;
	int   fft_length;
	int   source_ids[ARY_NUM_SRC];
	float source_coordinates[ARY_NUM_SRC];
#endif
	return this->RecvFromPortD(PortD_fd, &source_count, &fft_length, source_ids, source_coordinates, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortD(const int PortD_fd, jint *source_count, jint *fft_length, jint *source_ids, jdouble *source_coordinates, jdouble *source_spectra) const
#else
int ClientControlObject::RecvFromPortD(const int PortD_fd, int *source_count, int *fft_length, int *source_ids, float *source_coordinates, float *source_spectra) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			*source_count = 0;
			return(1);
		}
		else{
			LOGE("PortD recv ERROR");
			*source_count = 0;
			return(-1);
		}
	}
	else{
		// read OK
		if(hdr.type != PACKET_SRC_FFT){
			LOGE("FFT invalid header %d", hdr.type);
			*source_count = 0;
			return(-1);
		}
	}

	int data_num;
	readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&data_num), sizeof(data_num), NULL, NULL);
	if (readbyte != sizeof(data_num)) {
		*source_count = 0;
		return(-1);
	}
//#ifdef ENABLE_JNI_FOR_ANDROID
//    *source_count = static_cast<jint>(data_num);
//#else
//    *source_count = data_num;
//#endif // ENABLE_JNI_FOR_ANDROID

//	float data[((512 / 2) + 1) * 2 * 8];
//	for(int i = 0; i < data_num; i++) {
//		HDH_SrcInfo srcinfo;
//		readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
//		if (readbyte != sizeof(srcinfo)) {
//			return(-1);
//		}
//		HDH_SrcData srcdata;
//		readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&srcdata), sizeof(srcdata), NULL, NULL);
//		if (readbyte != sizeof(srcdata)) {
//			return(-1);
//		}
//		readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&data[i * 257 * 2]), sizeof(float) * 257 * 2, NULL, NULL);
//		if (readbyte != (sizeof(float) * 257 * 2)) {
//			return(-1);
//		}
//	}
	if(data_num > 0){
		int array_num = source_count[0] >> 1;
		if(array_num < data_num){
			LOGE("Array size is insufficient. recv = %d[sources], array = %d[sources]", data_num, array_num);
			*source_count = 0;
			return(-2);
		}
		else{
			HDH_SrcInfo srcinfo;
			HDH_SrcData srcdata;
			int offset_src  = 0;
			int offset_data = 0;
			float data[ARY_NUM_FFT * 2 * array_num]; //((length / 2) + 1) * 2 * num_src
			for(int i = 0; i < data_num; i++){
				readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&srcinfo), sizeof(HDH_SrcInfo), NULL, NULL);
				if(readbyte != sizeof(HDH_SrcInfo)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&srcdata), sizeof(HDH_SrcData), NULL, NULL);
				if(readbyte != sizeof(HDH_SrcData)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortD_fd, reinterpret_cast<void *>(&data[offset_data]), sizeof(float) * srcdata.length, NULL, NULL);
				if(readbyte != (sizeof(float) * srcdata.length)){
					*source_count = 0;
					return(-1);
				}
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_ids + i) = static_cast<jint>(srcinfo.src_id);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[0]);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[1]);
				//source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[2]);
				*(fft_length + i) = static_cast<jint>(srcdata.length);
#else
				*(source_ids + i) = srcinfo.src_id;
				source_coordinates[offset_src++] = srcinfo.x[0];
				source_coordinates[offset_src++] = srcinfo.x[1];
				//source_coordinates[offset_src++] = srcinfo.x[2];
				*(fft_length + i) = srcdata.length;
#endif // ENABLE_JNI_FOR_ANDROID
				offset_data += srcdata.length;
			}
			//LOGD("client datanum %d", data_num);
			for(int i = 0; i < offset_data; i++){ // offset_data == data_num * 257 * 2 // In order to adapt to the dynamic size.
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_spectra + i) = static_cast<jdouble>(data[i]);
#else
				*(source_spectra + i) = data[i];
#endif // ENABLE_JNI_FOR_ANDROID
			}
		}
	}

//	if(source_count[0] > data_num){
//		*source_count = data_num;
//	}
#ifdef ENABLE_JNI_FOR_ANDROID
	*source_count = static_cast<jint>(data_num);
#else
	*source_count = data_num;
#endif // ENABLE_JNI_FOR_ANDROID
	//LOGD("recv float %f", data[0]);

	return(0);
}

int ClientControlObject::ClosePortD(const int PortD_fd)
{
	::close(PortD_fd);
	return(0);
}


int ClientControlObject::ConnectPortE()
{
	int PortE_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_E);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortE_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortE_fd == -1) {
		LOGE("PortE socket error");
		return(-1);
	}

	// connect
	if (::connect(PortE_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortE connect error");
		close(PortE_fd);
		return(-1);
	}
	LOGD("connect PortE success");

	return(PortE_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortE(const int PortE_fd, jdouble *array) const
#else
int ClientControlObject::RecvFromPortE(const int PortE_fd, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint source_count, banks, source_ids[ARY_NUM_SRC];
	jdouble source_coordinates[ARY_NUM_SRC * 2];
#else
	int source_count, banks, source_ids[ARY_NUM_SRC];
	float source_coordinates[ARY_NUM_SRC * 2];
#endif
	return this->RecvFromPortE(PortE_fd, &source_count, &banks, source_ids, source_coordinates, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortE(const int PortE_fd, jint *source_count, jint *banks, jint *source_ids, jdouble *source_coordinates, jdouble *source_features) const
#else
int ClientControlObject::RecvFromPortE(const int PortE_fd, int *source_count, int *banks, int *source_ids, float *source_coordinates, float *source_features) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			*source_count = 0;
			return(1);
		}
		else{
			LOGE("PortE recv ERROR");
			*source_count = 0;
			return(-1);
		}
	}
	else{
		// read OK
		if(hdr.type != PACKET_SRC_FEATURE){
			LOGE("FEATURE invalid header %d", hdr.type);
			*source_count = 0;
			return(-1);
		}
	}

	int data_num;
	readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&data_num), sizeof(data_num), NULL, NULL);
	if(readbyte != sizeof(data_num)){
		*source_count = 0;
		return(-1);
	}
//#ifdef ENABLE_JNI_FOR_ANDROID
//    *source_count = static_cast<jint>(data_num);
//#else
//    *source_count = data_num;
//#endif // ENABLE_JNI_FOR_ANDROID

//	float data[13 * 2 * 8];
//	for(int i = 0; i < data_num; i++) {
//		HDH_SrcInfo srcinfo;
//		readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
//		if (readbyte != sizeof(srcinfo)) {
//			return(-1);
//		}
//		HDH_SrcData srcdata;
//		readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&srcdata), sizeof(srcdata), NULL, NULL);
//		if (readbyte != sizeof(srcdata)) {
//			return(-1);
//		}
//		readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&data[i * 13 * 2]), sizeof(float) * 13 * 2, NULL, NULL);
//		if (readbyte != (sizeof(float) * 13 * 2)) {
//			return(-1);
//		}
//	}

	if(data_num > 0){
		int array_num = source_count[0] >> 1;
		if(array_num < data_num){
			LOGE("Array size is insufficient. recv = %d[sources], array = %d[sources]", data_num, array_num);
			*source_count = 0;
			return(-2);
		}
		else{
			HDH_SrcInfo srcinfo;
			HDH_SrcData srcdata;
			int offset_src  = 0;
			int offset_data = 0;
			float data[28 * array_num];
			for(int i = 0; i < data_num; i++){
				readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
				if(readbyte != sizeof(srcinfo)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&srcdata), sizeof(srcdata), NULL, NULL);
				if(readbyte != sizeof(srcdata)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortE_fd, reinterpret_cast<void *>(&data[i * 13 * 2]), sizeof(float) * 13 * 2, NULL, NULL);
				if(readbyte != (sizeof(float) * 13 * 2)){
					*source_count = 0;
					return(-1);
				}
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_ids + i) = static_cast<jint>(srcinfo.src_id);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[0]);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[1]);
				//source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[2]);
				*(banks + i) = static_cast<jint>(srcdata.length);
#else
#endif // ENABLE_JNI_FOR_ANDROID
				offset_data += srcdata.length;
			}
			//LOGD("client datanum %d", data_num);
			for(int i = 0; i < offset_data; i++){ // offset_data == data_num * 257 * 2 // In order to adapt to the dynamic size.
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_features + i) = static_cast<jdouble>(data[i]);
#else
				*(source_features + i) = data[i];
#endif // ENABLE_JNI_FOR_ANDROID
			}
		}
	}

//	if(source_count[0] > data_num){
//		*source_count = data_num;
//	}
#ifdef ENABLE_JNI_FOR_ANDROID
	*source_count = static_cast<jint>(data_num);
#else
	*source_count = data_num;
#endif // ENABLE_JNI_FOR_ANDROID
	//LOGD("recv float %f", data[0]);

	return(0);
}

int ClientControlObject::ClosePortE(const int PortE_fd)
{
	::close(PortE_fd);
	return(0);
}

int ClientControlObject::ConnectPortF() // NAKAMURA
{
	int PortF_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_F);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortF_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortF_fd == -1) {
		LOGE("PortF socket error");
		return(-1);
	}

	// connect
	if (::connect(PortF_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortF connect error");
		close(PortF_fd);
		return(-1);
	}
	LOGD("connect PortF success");

	return(PortF_fd);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortF(const int PortF_fd, jdouble *array) const
#else
int ClientControlObject::RecvFromPortF(const int PortF_fd, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint source_count, advance, source_ids[ARY_NUM_SRC];
	jdouble source_coordinates[ARY_NUM_SRC * 2];
#else
	int source_count, advance, source_ids[ARY_NUM_SRC];
	float source_coordinates[ARY_NUM_SRC * 2];
#endif
	return this->RecvFromPortF(PortF_fd, &source_count, &advance, source_ids, source_coordinates, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortF(const int PortF_fd, jint *source_count, jint *advance, jint *source_ids, jdouble *source_coordinates, jdouble *source_acoustics) const
#else
int ClientControlObject::RecvFromPortF(const int PortF_fd, int *source_count, int *advance, int *source_ids, float *source_coordinates, float *source_acoustics) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000 * 250; // 0.25
	int isTimeoutOccured;
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			*source_count = 0;
			return(1);
		}
		else{
			LOGE("PortF recv ERROR");
			*source_count = 0;
			return(-1);
		}
	}
	else{
		// read OK
		if(hdr.type != PACKET_SRC_FFT){
			LOGE("FFT invalid header %d", hdr.type);
			*source_count = 0;
			return(-1);
		}
	}

	int data_num;
	readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&data_num), sizeof(data_num), NULL, NULL);
	if(readbyte != sizeof(data_num)){
		*source_count = 0;
		return(-1);
	}
//#ifdef ENABLE_JNI_FOR_ANDROID
//    *source_count = static_cast<jint>(data_num);
//#else
//    *source_count = data_num;
//#endif // ENABLE_JNI_FOR_ANDROID

	/* 2013.08.21 K.Takagi
	 *   ADVANCEを可変にするため実際のデータ長はデータヘッダより取得
	 */

	if(data_num > 0){
		int array_num = source_count[0] >> 1;
		if(array_num < data_num){
			LOGE("Array size is insufficient. recv = %d[sources], array = %d[sources]", data_num, array_num);
			*source_count = 0;
			return(-2);
		}
		else{
			HDH_SrcInfo srcinfo;
			HDH_SrcData srcdata;
			int offset_src  = 0;
			int offset_data = 0;
			float data[_ADVANCE_VAL_ * 8];
			for(int i = 0; i < data_num; i++){
				readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
				if(readbyte != sizeof(srcinfo)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&srcdata), sizeof(srcdata), NULL, NULL);
				if(readbyte != sizeof(srcdata)){
					*source_count = 0;
					return(-1);
				}
				readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&data[i * srcdata.length]), sizeof(float) * srcdata.length, NULL, NULL);
				if(readbyte != (sizeof(float) * srcdata.length)){
					*source_count = 0;
					return(-1);
				}
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_ids + i) = static_cast<jint>(srcinfo.src_id);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[0]);
				source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[1]);
				//source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[2]);
				*(advance + i) = static_cast<jint>(srcdata.length);
#else
				*(source_ids + i) = srcinfo.src_id;
				source_coordinates[offset_src++] = srcinfo.x[0];
				source_coordinates[offset_src++] = srcinfo.x[1];
				//source_coordinates[offset_src++] = srcinfo.x[2];
				*(advance + i) = srcdata.length;
#endif // ENABLE_JNI_FOR_ANDROID
				offset_data += srcdata.length;
			}
			//LOGD("client datanum %d", data_num);
			for(int i = 0; i < offset_data; i++){ // offset_data == data_num * _ADVANCE_VAL_ // In order to adapt to the dynamic size.
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_acoustics + i) = static_cast<jdouble>(data[i]);
#else
				*(source_acoustics + i) = data[i];
#endif // ENABLE_JNI_FOR_ANDROID
			}
		}
	}

//	if(source_count[0] > data_num){
//		*source_count = data_num;
//	}
#ifdef ENABLE_JNI_FOR_ANDROID
	*source_count = static_cast<jint>(data_num);
#else
	*source_count = data_num;
#endif // ENABLE_JNI_FOR_ANDROID
	//LOGD("recv float %f", data[0]);

	return(0);
}

int ClientControlObject::ClosePortF(const int PortF_fd)
{
	::close(PortF_fd);
	return(0);
}

int ClientControlObject::ConnectPortFwithSrc() // TAKIGAHIRA
{
	int PortF_fd;

	struct sockaddr_in dstAddr;
	::memset(&dstAddr, 0, sizeof(dstAddr));
	dstAddr.sin_port = htons(HA_PORT_F);
	dstAddr.sin_family = AF_INET;
	dstAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	PortF_fd = ::socket(AF_INET, SOCK_STREAM, 0);
	if (PortF_fd == -1) {
		LOGE("PortF socket error");
		return(-1);
	}

	// connect
	if (::connect(PortF_fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		LOGE("PortF connect error");
		close(PortF_fd);
		return(-1);
	}
	LOGD("connect PortF success");

	return(PortF_fd);
}


#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortFwithSrc(const int PortF_fd, jint *array_src, jdouble *array) const
#else
int ClientControlObject::RecvFromPortFwithSrc(const int PortF_fd, int *array_src, float *array) const
#endif // ENABLE_JNI_FOR_ANDROID
{
#ifdef ENABLE_JNI_FOR_ANDROID
	jint source_count, advance;
	jdouble source_coordinates[ARY_NUM_SRC];
#else
	int source_count, advance;
	float source_coordinates[ARY_NUM_SRC];
#endif
	return this->RecvFromPortFwithSrc(PortF_fd, &source_count, &advance, array_src, source_coordinates, array);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ClientControlObject::RecvFromPortFwithSrc(const int PortF_fd, jint *source_count, jint *advance, jint *source_ids, jdouble *source_coordinates, jdouble *source_acoustics) const
#else
int ClientControlObject::RecvFromPortFwithSrc(const int PortF_fd, int *source_count, int *advance, int *source_ids, float *source_coordinates, float *source_acoustics) const
#endif // ENABLE_JNI_FOR_ANDROID
{
	timeval timeout;
	timeout.tv_sec = 0;
	//timeout.tv_usec = 1000 * 250; // 0.25
	timeout.tv_usec = 250000; // 0.25sec=>1000*250usec=>250000usec TAKIGAHIRA
	int isTimeoutOccured;
	::HD_Header hdr;
	ssize_t readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&hdr), sizeof(hdr), &timeout, &isTimeoutOccured);
	if(readbyte != sizeof(hdr)){
		if(isTimeoutOccured){
			*source_count = 0;
			return(1);
		}
		else{
			LOGE("PortF recv ERROR");
			*source_count = 0;
			return(-1);
		}
	}
	else{
		// read OK
		if(hdr.type != PACKET_SRC_FFT){
			LOGE("FFT invalid header %d", hdr.type);
			*source_count = 0;
			return(-1);
		}
	}

	int data_num;
	readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&data_num), sizeof(data_num), NULL, NULL);
	if(readbyte != sizeof(data_num)){
		*source_count = 0;
		return(-1);
	}
	//LOGD("client datanum %d", data_num);
#ifdef ENABLE_JNI_FOR_ANDROID
    *source_count = static_cast<jint>(data_num);
#else
    *source_count = data_num;
#endif // ENABLE_JNI_FOR_ANDROID

	/* 2013.08.21 K.Takagi
	 *   ADVANCEを可変にするため実際のデータ長はデータヘッダより取得
	 */

	if(data_num == 0){
#ifdef ENABLE_JNI_FOR_ANDROID
		*(source_ids) = static_cast<jint>(-1);
		//for(int j=0; j<_ADVANCE_VAL_; j++) {
		//	*(source_ids + j) = static_cast<jdouble>(0.0f);
		//}
#else
		*(source_ids) = static_cast<int>(-1);
		//for(int j=0; j<_ADVANCE_VAL_; j++) {
		//	*(source_ids + j) = static_cast<float>(0.0f);
		//}
#endif
	}
	else{
		HDH_SrcInfo srcinfo;
		HDH_SrcData srcdata;
		int offset_src  = 0;
		int offset_data = 0;
		float data[_ADVANCE_VAL_];
		for(int i = 0; i < data_num; i++) {
			readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&srcinfo), sizeof(srcinfo), NULL, NULL);
			if(readbyte != sizeof(srcinfo)){
				*source_count = 0;
				return(-1);
			}
			readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(&srcdata), sizeof(srcdata), NULL, NULL);
			if(readbyte != sizeof(srcdata)){
				*source_count = 0;
				return(-1);
			}
			readbyte = ::readsock(PortF_fd, reinterpret_cast<void *>(data), sizeof(float) * srcdata.length, NULL, NULL);
			if(readbyte != (sizeof(float) * srcdata.length)){
				*source_count = 0;
				return(-1);
			}
#ifdef ENABLE_JNI_FOR_ANDROID
			*(source_ids + i) = static_cast<jint>(srcinfo.src_id);
			source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[0]);
			source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[1]);
			//source_coordinates[offset_src++] = static_cast<jdouble>(srcinfo.x[2]);
			*(advance + i) = static_cast<jint>(srcdata.length);
#else
			*(source_ids + i) = srcinfo.src_id;
			source_coordinates[offset_src++] = srcinfo.x[0];
			source_coordinates[offset_src++] = srcinfo.x[1];
			//source_coordinates[offset_src++] = srcinfo.x[2];
			*(advance + i) = srcdata.length;
#endif
			for(int j=0, offset=i*srcdata.length; j<srcdata.length; j++){
#ifdef ENABLE_JNI_FOR_ANDROID
				*(source_acoustics + offset + j) = static_cast<jdouble>((double)data[j]);
#else
				*(source_acoustics + offset + j) = data[j];
#endif
				//LOGD("recv float offset:%d i:%d %f j:%d %f", offset, i, *(array + offset + j), j, data[j]);
			}
			//LOGD("recv float %f", data[0]);
		}
	}

	return(0);
}

int ClientControlObject::ClosePortFwithSrc(const int PortF_fd)
{
	::close(PortF_fd);
	return(0);
}

bool ClientControlObject::isStop()
{
	lockobject lock(&Stop_mutex);

	const bool val = Stopped;

	return(val);
}

int ClientControlObject::SetStop()
{
	lockobject lock(&Stop_mutex);

	Stopped = true;

	return(0);
}

int ClientControlObject::ResetStop()
{
	lockobject lock(&Stop_mutex);

	Stopped = false;

	return(0);
}


} // end of namespace
