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

#include "HA_config.h"
#include "HA_log.h"
#include "HA_port.h"
#include "socketutil.h"
//////////#include "header.h"
#include "julius.h"
//#include "HA_ControlObject.h"


static int connectToServer(const char * const hostname, const int port)
{

	int fd;

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

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

	// connect
	if (::connect(fd, (struct sockaddr *) &dstAddr, sizeof(dstAddr)) != 0) {
		/* Juliusが起動していない場合もあるのでエラー表示をコメントアウト */
		//LOGE("JuliusMFT connect error %s", hostname);
		close(fd);
		return(-1);
	}

	return(fd);
}

int sendASRParam(const char * const hostname, const int port, const SourceInfo &arg_src_info, const std::vector<feature> &features)
{

	// timeval の各要素が32bitで、juliusサーバー側とサイズが合わないようなのでワークアラウンド
	struct local_timeval {
		long long tv_sec;
		long long tv_usec;
	};
	struct local_src_info {
		int source_id;
		float azimuth;
		float elevation;
		local_timeval time;
	} __attribute__((packed));


	const int socket_fd = ::connectToServer(hostname, port);

	/* 2013.02.15 サーバに接続できなかったら何もしない */
	if(socket_fd < 0)
	{
		return -1;
	}

	local_src_info src_info;
	src_info.source_id = arg_src_info.source_id;
	src_info.azimuth   = arg_src_info.azimuth;
	src_info.elevation = arg_src_info.elevation;
	src_info.time.tv_sec = arg_src_info.time.tv_sec;
	src_info.time.tv_usec = arg_src_info.time.tv_usec;

	std::vector<float> mask(ARY_NUM_FBANK_DELTA_P_ERASE);
	for(int i = 0; i < mask.size(); i++) {
		mask[i] = 1.0;
	}

	const int s_src_info = sizeof(src_info);

	::writesock(socket_fd, &s_src_info, sizeof(s_src_info), NULL, NULL);
	::writesock(socket_fd, &src_info, sizeof(src_info), NULL, NULL);

	const int s_mask = mask.size() * sizeof(float);

	feature ave;
//    	LOGD("srcinfo %d feature %d mask %d", s_src_info, s_features, s_mask);
//    	LOGD("feature size %d", sizeof(features[0].feature));
//    	LOGD("features.size() %d", features.size()); // フレーム数
//    	LOGD("NELEM(ave.feature) %d", NELEM(ave.feature)); // 27 = ARY_NUM_FBANK_DELTA_P_ERASE = fbank_count * 2 + 1

//	LOGD("features[0].feature");
//	for(int i = 0; i < NELEM(ave.feature); i++) {
//		LOGD("  %f", features[0].feature[i]);
//	}

	// 静的特徴量部のみを平均除去
	for(int i = 0; i < NELEM(ave.feature); i++) {
		ave.feature[i] = 0;
	}
	for(int i = 0; i < features.size(); i++) {
		for(int j = 0; j < NELEM(ave.feature)/2; j++) {
			ave.feature[j] += features[i].feature[j];
		}
	}
	for(int i = 0; i < NELEM(ave.feature)/2; i++) {
		ave.feature[i] /= features.size();
	}

	for(int i = 0; i < features.size(); i++) {

		feature send;
		//for(int j = 0; j < NELEM(send.feature); j++) {
		//	send.feature[j] = 0;
		//}

		for(int j = 0; j < NELEM(send.feature); j++) {
			send.feature[j] = features[i].feature[j] - ave.feature[j];
		}

		::writesock(socket_fd, &s_mask, sizeof(s_mask), NULL, NULL);
		::writesock(socket_fd, send.feature, s_mask, NULL, NULL);

		::writesock(socket_fd, &s_mask, sizeof(s_mask), NULL, NULL);
		::writesock(socket_fd, &mask[0], s_mask, NULL, NULL);
		//::writesock(socket_fd, send.feature, s_mask, NULL, NULL); // 2013.02.06 K.Takagi マスクも同じ値を送る

	}

	const int delim(0);
	::writesock(socket_fd, &delim, sizeof(delim), NULL, NULL);

	::close(socket_fd);

	return(0);
}
