/* ***********************IMPORTANT *********************************************
 *  Copyright (C) 2004-2007 Thierry Lagarde <tlagarde@users.sourceforge.net>
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License.
 *
 *
 *                      ********************
 *
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *
 *                      ********************
 *
 *
 * You are highly encouraged to send your changes to <tlagarde@users.sourceforge.net>
 * for possible incorporation into the main distribution.
 * By sending these changes to <tlagarde@users.sourceforge.net>,
 * it is assumed that you are offering <tlagarde@users.sourceforge.net>
 * the unlimited, non-exclusive right to reuse, modify, and relicense the code.
 *
 *
 *                      ********************
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **************************************************************************************/
#ifdef         __SCRIPT_ENABLE
#include <sys/msg.h>
#endif
#include "Commun.h"
#include "../Debug.h"
#include "Initialisation_Com.h"
#include "../Reseau.h"
#include "Communication.h"
#include "../Log.h"
#include "../Macro.h"

extern struct Struct_Modele_Communication Liste_Communication[];
	

gint Calculer_Ckecksum(gint *Donnee, gint Taille_Donnee){
	gint i,Ckecksum;
	
	Ckecksum = 0;
	for (i=0;i<(Taille_Donnee/sizeof(gint));i++)
		Ckecksum = Donnee[i] + Ckecksum;
		
	return Ckecksum;
}

void Log_Envoie_Transmission(struct Struct_Liste_Reseau *Reseau,gchar *Texte_Log){
	if (Reseau!=NULL)
		Log(Reseau->Log_Send,Texte_Log);
	MYFREE(Texte_Log);
}


gboolean Socket_Send_Ok(int socket,struct Struct_Liste_Reseau *Reseau){
	fd_set fd_read,fd_write;
	socklen_t lon; 
    struct timeval tv;
	int retval,valopt,TimeOut;

	TimeOut = 0;
	do {
	
	
	
	
	
		FD_ZERO(&fd_write);
		FD_SET(socket, &fd_write);
	
   		tv.tv_sec = 1;
    	tv.tv_usec = 0;
 		retval = select(socket + 1,NULL, &fd_write, NULL, &tv);
    	if (retval==1){
		
    		lon = sizeof(int); 
    		if (getsockopt(socket, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
#ifdef __DEBUG_COM
			Log_Envoie_Transmission(Reseau,g_strdup_printf("Error in getsockopt() %d - %s\n", errno, strerror(errno)));
#endif
				debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); 
            	return FALSE;
			} 
			if (valopt) { 
#ifdef __DEBUG_COM
				Log_Envoie_Transmission(Reseau,g_strdup_printf("Error in delayed connection() %d - %s", valopt, strerror(valopt)));
#endif
				debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Error in delayed connection() %d - %s",valopt, strerror(valopt)); 
				return FALSE;
			} 
#ifdef __DEBUG_COM
			Log_Envoie_Transmission(Reseau,g_strdup_printf(" Ecriture ...\n"));
#endif
			return TRUE;
		}
    	else {
#ifdef __DEBUG_COM
			Log_Envoie_Transmission(Reseau,g_strdup_printf("Impossible d'ecrire depuis 1 secondes  retval=%d",retval));
#endif
			debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Impossible d'ecrire depuis 1 secondes  retval=%d",retval);
			sleep(1);
		}
	
		TimeOut++;
	} while (TimeOut <= 5);
	return FALSE;	
	/*
	struct pollfd fds[1];
	int       resultat,TimeOut;
	
	TimeOut = 0;
	do {
		bzero (&fds, sizeof fds);
		fds[0].events = POLLOUT;
		fds[0].fd = socket;	
		if ((resultat = poll (&fds, 1, 1000)) > 0) {
			if (fds[0].revents & POLLOUT){
			
				return TRUE;
			}
		}
		else {
			if (resultat != 0){
				debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Socket error : (%d)  [%s]", socket,strerror (errno));
			}
			debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Poll non pret depuis 1 secondes\n");
		}
#ifdef __DEBUG_COM
		Log_Envoie_Transmission(Reseau,g_strdup_printf("Tentative envoie donnée Agent : TimeOut n°[%d] resultat (%d) error[%s]\n", TimeOut,resultat,strerror (errno)));
#endif
		debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Tentative envoie donnée Agent : TimeOut n°[%d] resultat (%d) error[%s]", TimeOut,resultat,strerror (errno));
		TimeOut++;
	} while (TimeOut <= 5);
	return FALSE;	
	*/
}


void Communication_Envoie_Donnee (gint Pid_Agent, gint ID_Info, gpointer * Donnee, gint Taille_Donnee, struct Struct_Liste_Reseau *Reseau)
{
	struct struct_Info Info;
	struct struct_Info_TCP Info_TCP;
	int NbOctet,Socket;
	gchar *Texte_Log;
	
	
#ifdef         __SCRIPT_ENABLE

	if ((ID_Info==RETOUR_SCRIPT) || (ID_Info==RETOUR_SCRIPT_TERMINER)){
		if ((Taille_Donnee + sizeof (gint)) >= TAILLE_MAX_DONNEE_BRUT)
			debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille du message >=%d",TAILLE_MAX_DONNEE_BRUT);
		Info.type = Pid_Agent;	
		Info.ID_Info = ID_Info;
		memcpy (Info.Donnee, Donnee, Taille_Donnee);
		if (msgsnd (File_Info, (void *) &Info, (Taille_Donnee + sizeof (gint)), 0) < 0)
			printf ("msgsnd : %s\n", strerror (errno));
		return;
	}
#endif

	
	if ((Taille_Donnee + sizeof (gint)) >= TAILLE_MAX_DONNEE_BRUT)
		debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Taille du message >=%d",TAILLE_MAX_DONNEE_BRUT);
	if (Reseau != NULL)
		Reseau->Octet_Envoyer_Agent = Reseau->Octet_Envoyer_Agent + Taille_Donnee;
	Info_TCP.ID_Info = ID_Info;
	Info_TCP.Taille_Donnee = Taille_Donnee;	
	Info_TCP.Ckecksum = Calculer_Ckecksum(Donnee,Taille_Donnee);
	memcpy (Info_TCP.Donnee, Donnee, Taille_Donnee);
#ifdef __DEBUG_COM
	
		Log_Envoie_Transmission(Reseau,g_strdup_printf("[%s] %d\n[%s] Ckecksum %08X\n",Liste_Communication[ID_Info].Debug,Taille_Donnee,Liste_Communication[ID_Info].Debug,Info_TCP.Ckecksum));
#endif
	if (Reseau!=NULL)
		Socket = Reseau->Socket_Agent;
	else
		Socket = Socket_Agent_Init;

	if (!Socket_Send_Ok(Socket,Reseau)){
#ifdef __DEBUG_COM
		Log_Envoie_Transmission(Reseau,g_strdup_printf("[%s] %d\n[%s] Ckecksum %08X #### send (Resource temporarily unavailable)\n",Liste_Communication[ID_Info].Debug,Taille_Donnee,Liste_Communication[ID_Info].Debug,Info_TCP.Ckecksum));
#endif
		debug_printf (INTERFACE, D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "send (Resource temporarily unavailable)\n");
	}
	NbOctet = send (Socket, &Info_TCP, sizeof (struct struct_Info_Entete)+Taille_Donnee, 0);
	if (NbOctet < 0){
#ifdef __DEBUG_COM
		Log_Envoie_Transmission(Reseau,g_strdup_printf("[%s] %d\n[%s] Ckecksum %08X   #### send NbOctet < 0  (%d)[%s]\n",Liste_Communication[ID_Info].Debug,Taille_Donnee,Liste_Communication[ID_Info].Debug,Info_TCP.Ckecksum,errno, strerror (errno)));
#endif
		Reseau->Connection_Failed = TRUE;
		debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "send NbOctet < 0  (%d)[%s]", errno, strerror (errno)); 
	}
	if (NbOctet != (sizeof (struct struct_Info_Entete)+Taille_Donnee)){
#ifdef __DEBUG_COM
		Log_Envoie_Transmission(Reseau,g_strdup_printf("[%s] %d\n[%s] Ckecksum %08X   #### send NbOctet != (sizeof (struct struct_Info_Entete)+Taille_Donnee) (%d)[%s]\n",Liste_Communication[ID_Info].Debug,Taille_Donnee,Liste_Communication[ID_Info].Debug,Info_TCP.Ckecksum,errno, strerror (errno)));
#endif	
		debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "send NbOctet != (sizeof (struct struct_Info_Entete)+Taille_Donnee) (%d)[%s]", errno, strerror (errno)); 
	}
}
