/* ***********************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.
 **************************************************************************************/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include "Log.h"
#include "Debug.h"
#include "Animation.h"
#include "Update.h"
#include "Sound.h"
#include "Smtp.h"
#include "Contribution.h"
#include "BackTrace.h"
#include "main.h"
#include "Semaphore.h"
#include "Macro.h"
#include "Com/Commun.h"

#ifdef __LOG_ENABLE

struct Struct_Categorie Liste_Categorie[] = {
	{CATEG_MAIN, "CATEG_MAIN", REPERTOIRE_LOG "main_gui",-1,0,FALSE},
	{CATEG_THREAD_CONTRIBUTION, "CATEG_THREAD_CONTRIBUTION", REPERTOIRE_LOG "Contribution",-1,0,FALSE},
	{CATEG_THREAD_SOUND, "CATEG_THREAD_SOUND", REPERTOIRE_LOG "sound",-1,0,FALSE},
	{CATEG_THREAD_TEST_VERSION, "CATEG_THREAD_TEST_VERSION", REPERTOIRE_LOG "check_version",-1,0,FALSE},
	{CATEG_THREAD_ENVOIE_EMAIL, "CATEG_THREAD_ENVOIE_EMAIL", REPERTOIRE_LOG "send_mail",-1,0,FALSE},
	{CATEG_THREAD_UPDATE_FINGERPRINTING, "CATEG_THREAD_UPDATE_FINGERPRINTING", REPERTOIRE_LOG "update",-1,0,FALSE},
	{CATEG_COMM_SEND, "CATEG_COMM_SEND", REPERTOIRE_LOG "send_%s",-1,0,FALSE},
	{CATEG_COMM_RECV, "CATEG_COMM_RECV", REPERTOIRE_LOG "recv_%s",-1,0,FALSE},
};


void create_cle_privee (void)
{
	if (pthread_key_create (&Cle_privee_thread, NULL) == -1)
		debug_printf (INTERFACE, D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "pthread_key_create");
}

void Initialisation_Log (void)
{
	init_backtrace();
	once_cle_privee=PTHREAD_ONCE_INIT;

	Donnee_Cle_Main = Create_Log(CATEG_MAIN,NULL,NULL,TRUE);
}

#endif  



void Log (struct struct_Cle_Privee *Donnee_Cle,gchar *Log){
#ifdef __LOG_ENABLE
	ERROR_if (Donnee_Cle == NULL);
	ERROR_if (Log == NULL);
	PROTECT_CODE(Semaphore_Log_File);
	gint Taille_Chaine;
	
	if (Donnee_Cle->ID_Fichier_Log > 0){
	
		Taille_Chaine = strlen(Log);
		if (Taille_Chaine!=write(Donnee_Cle->ID_Fichier_Log,Log,Taille_Chaine)){
			printf("ERROR : Create log  (write)\n");
			DEPROTECT_CODE(Semaphore_Log_File);
			exit (-1);
		}
	}
	DEPROTECT_CODE(Semaphore_Log_File);
#endif	
}


void Log_free (struct struct_Cle_Privee *Donnee_Cle,gchar *Texte){
	if (Texte != NULL){
#ifdef __LOG_ENABLE
		Log(Donnee_Cle,Texte);
#endif	
		MYFREE(Texte);
	}
}


struct struct_Cle_Privee *Create_Log (gint Categorie,gchar *name,void *Data,gboolean Attache_Thread){
#ifdef __LOG_ENABLE
	PROTECT_CODE(Semaphore_Log_File);	
	struct struct_Cle_Privee *Donnee_Cle = NULL;
	gchar	*Fichier_Log = NULL;
	
	if (Attache_Thread)
		pthread_once(&once_cle_privee,create_cle_privee);
	MALLOC(Donnee_Cle,sizeof(struct struct_Cle_Privee));
	Donnee_Cle->Categorie = Categorie;
	Donnee_Cle->Pointeur_Data = Data;


	if ((Liste_Categorie[Categorie].used==0) || (name!=NULL)) {
		if (name!=NULL)
			Fichier_Log = g_strdup_printf(Liste_Categorie[Categorie].Fichier_Log,Info_User->pw_dir,name);
		else	
			Fichier_Log = g_strdup_printf (Liste_Categorie[Categorie].Fichier_Log, Info_User->pw_dir);
	
		
		if (Liste_Categorie[Categorie].deja_ouvert)
			Donnee_Cle->ID_Fichier_Log = open(Fichier_Log, O_WRONLY | O_CREAT | O_APPEND , 0644);
		else
			Donnee_Cle->ID_Fichier_Log = open(Fichier_Log, O_WRONLY | O_CREAT | O_TRUNC , 0644);
		if (Donnee_Cle->ID_Fichier_Log<0){
			printf("ERROR : Create log  (open)  %s\n",Fichier_Log);
			MYFREE(Fichier_Log);
			DEPROTECT_CODE(Semaphore_Log_File);
			return NULL;
		}
		if (name == NULL)
			Liste_Categorie[Categorie].deja_ouvert = TRUE; 
		MYFREE(Fichier_Log);
	}
	else {
	
		Donnee_Cle->ID_Fichier_Log = Liste_Categorie[Categorie].ID_Fichier_Log;
	}

	if (name == NULL)
		Liste_Categorie[Categorie].used++;
	
	if (Attache_Thread)
		pthread_setspecific(Cle_privee_thread,Donnee_Cle);
	DEPROTECT_CODE(Semaphore_Log_File);
	
	Log_free(Donnee_Cle,g_strdup_printf("---------------------------------------\n------- %s ------\n---------------------------------------\n\n\n",Liste_Categorie[Categorie].Info));
	return Donnee_Cle;
#endif
}




void Close_Log_Thread (struct struct_Cle_Privee *Donnee_Cle){
#ifdef __LOG_ENABLE
	ERROR_if(Donnee_Cle == NULL);
	Log(Donnee_Cle,"########## Close\n");
	ERROR_if(Liste_Categorie[Donnee_Cle->Categorie].used <= 0);
	PROTECT_CODE(Semaphore_Log_File);
	if (Liste_Categorie[Donnee_Cle->Categorie].used == 1) { 
		
		if (Donnee_Cle->ID_Fichier_Log==0) {
			printf("Error : close (%s)\n",Liste_Categorie[Donnee_Cle->Categorie].Fichier_Log);
			DEPROTECT_CODE(Semaphore_Log_File);
		return;
		}
		close(Donnee_Cle->ID_Fichier_Log);		
		Donnee_Cle->ID_Fichier_Log = 0;
		Liste_Categorie[Donnee_Cle->Categorie].ID_Fichier_Log = -1;
	
	}


	Liste_Categorie[Donnee_Cle->Categorie].used--;		
	DEPROTECT_CODE(Semaphore_Log_File);
#endif
}


void Ckeck_Fermeture_Log (){
#ifdef __LOG_ENABLE
	gint i;
	
	for (i=0;i<NB_CATEGORIE_DEBUG;i++)
		if (Liste_Categorie[i].used!=0)
				printf("ERROR : Close log [%s]\n",Liste_Categorie[i].Info);
#endif
}


void Close_Log_Main(){
#ifdef __LOG_ENABLE
	Close_Log_Thread(Donnee_Cle_Main);
#endif
}



void Envoie_Email_Segfault(struct struct_Cle_Privee *pCle){
#ifdef __LOG_ENABLE
	gchar Info[TAILLE_INFO_ERREUR_CRITIQUE],*line[BUFSIZ],*Chemin;
	FILE *fd = NULL;
	gint Taille_Fichier,A_Lire;
	
	Chemin = g_strdup_printf (Liste_Categorie[pCle->Categorie].Fichier_Log, Info_User->pw_dir);

	sprintf (Info, "Segfault : Invalid memory reference (%s)\n\nFichier : (%s)\nFonction : (%s)   \n\nAction_Utilisateur\n (%s) (%s)\n", Liste_Categorie[pCle->Categorie].Info,File_Debug,Fonction_Debug,File_Action_User,Fonction_Action_User);

	if ((fd=fopen(Chemin,"r+")) != NULL){
	
		fseek(fd,0,SEEK_END);
	
		Taille_Fichier = ftell(fd);
	
		if (Taille_Fichier<=TAILLE_INFO_ERREUR_CRITIQUE){
			fseek(fd,0,SEEK_SET);
			A_Lire = Taille_Fichier;
		}
		else {
			fseek(fd,Taille_Fichier-TAILLE_INFO_ERREUR_CRITIQUE,SEEK_SET);
			A_Lire = TAILLE_INFO_ERREUR_CRITIQUE;
		}
		while (fgets(line,A_Lire,fd)){
			strcat (Info, line);
		}
		fclose(fd);
		contribution_Erreur (Info);
	}
	else
		printf("Impossible d'ouvrir le fichier log de l'interface %s\n",Liste_Categorie[pCle->Categorie].Fichier_Log);
	MYFREE(Chemin);
#endif
}

void Initialisation_Repertoire_Log(){
#ifdef __LOG_ENABLE
	DIR      *dir = NULL;
	gchar    *Chemin = NULL;
	

	Chemin = g_strdup_printf ("%s/.autoscan-network", Info_User->pw_dir);

	dir = opendir (Chemin);
	if (dir == NULL) {
	
	
		if (mkdir (Chemin, 0700) != 0) {
			printf("ERROR : Creating folder: %s: %s\n", Chemin, strerror (errno));
			exit (1);
		}
		dir = opendir (Chemin);
		if (dir == NULL) {
			printf("ERROR : %s not found\n", Chemin);
			exit (-1);
		}
	}
	closedir (dir);
	MYFREE (Chemin);
	
	
	Chemin = g_strdup_printf (REPERTOIRE_LOG, Info_User->pw_dir);
	dir = opendir (Chemin);
	if (dir == NULL) {
	
		if (mkdir (Chemin, 0766) != 0) {
			printf("ERROR : Creating folder: %s: %s\n", Chemin, strerror (errno));
			exit (-1);
		}
		dir = opendir (Chemin);
		if (dir == NULL) {
			printf("ERROR : %s not found\n", Chemin);
			exit (-1);
		}
	}
	closedir (dir);
	MYFREE (Chemin);
#endif
}
