#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gestionUM2024.h"

// Global variable definitions (declared as extern in gestionUM2024.h)
FILE *fptrum_2024;
UMINFO_2024 uminf_2024[MAX_UM_2024];
int nbuminf_2024;
int indice_ums_2024[tab_max];
int indice_um$$$$_2024;
autref_2024 umrefs_2024;
autref_2024 litdedref_2024;
intervallesAutor_2024 plagesAutor_2024[tab_max];

#define CRC32_POLY_2024 0x04c11db7
unsigned long crc32_table_2024[256];

int getindicetypUM_2024(char typum[])
{
    char ltypum[3];
    strncpy(ltypum,typum,2);
    ltypum[2]=0;
    return atoi(ltypum);
}

void init_crc32_2024()
{
	int i, j;
	unsigned long c;

	for (i = 0; i < 256; ++i) {
		for (c = i << 24, j = 8; j > 0; --j)
			c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY_2024 : (c << 1);
		crc32_table_2024[i] = c;
	}
}
void signer_IUM_2024(unsigned char *buf[], int nbium,unsigned char *res)
{
	unsigned char *p;
	unsigned long  crc;
	int i,len;
    static int initcrc32_2024 = 0;
	
    if(!initcrc32_2024)
    {
        init_crc32_2024();
        initcrc32_2024=1;
    }
	crc = 0xffffffff;
	for(i=0;i<nbium;i++)
	{
		p=buf[i];
		len=strlen(p);
		for (p; len > 0; ++p, --len){
            // IMPORTANT: We changed the initial implementation 
            // crc = (crc << 8) ^ crc32_table_2024[(crc >> 24) ^ ToAscii_2024(*p)];
		    if(p == NULL) {
		        printf("ERROR: p became NULL during character loop\n");
		        return;
		    }
		    crc = (crc << 8) ^ crc32_table_2024[((crc >> 24) & 0xFF) ^ ToAscii_2024((unsigned char)*p)];
        }
	}
	sprintf (res, "%010u",~crc);
}
int verifFichierUMsigne_2024()
{
    int eof;
    char buf[101];
    char buf2[101];
    int i,t;
    unsigned char signature[TAILLE_SIGNATURE_2024+1];
    int lgligne,nbligne;
    char *uminfs[MAX_LIGNE_UM_2024+1];
    
    eof=0;
    t=TAILLE_LIGNE_UM_2024;
    memset(buf,0,sizeof(buf));
    memset(buf2,0,sizeof(buf2));
    memset(uminfs,0,MAX_LIGNE_UM_2024+1);
    fseek(fptrum_2024,0,SEEK_SET);
    nbligne=0;
    while(!eof)
    {
        if(mfgets_2024(buf,100,fptrum_2024)==0)
        {
            eof=1;
            continue;
        }
        lgligne = strlen(buf);
        if(lgligne!=t)
        {
            strncpy(buf2,buf,lgligne);
            if(mfgets_2024(buf,100,fptrum_2024)!=0)
            {
                for(i=0;i<nbligne;i++)
                {
                    if(uminfs[i]!=NULL)
                        free(uminfs[i]);
                }
                return 501;
            }
            /*on est sur la signature*/
            uminfs[nbligne]=(char*)malloc(lgligne+1);
            strncpy(uminfs[nbligne],buf2,lgligne);
            *(uminfs[nbligne]+lgligne)=0;
            nbligne++;
            eof=1;
        }
        else
        {
            uminfs[nbligne]=(char*)malloc(TAILLE_LIGNE_UM_2024+1);
            // IMPORTANT: We changed the initial implementation 
            if(uminfs[nbligne] == NULL) {
                printf("ERROR: Failed to allocate memory for UM line\n");
                for(i=0;i<nbligne;i++)
                {
                    if(uminfs[i]!=NULL)
                        free(uminfs[i]);
                }
                return 501;
            }
            strncpy(uminfs[nbligne],buf,TAILLE_LIGNE_UM_2024);
            *(uminfs[nbligne]+TAILLE_LIGNE_UM_2024)=0;
            nbligne++;
        }
    }
    if(nbligne<1)
        return 501;
    /*verifier la taille de la signature*/
    if(strlen(uminfs[nbligne-1])!=TAILLE_SIGNATURE_2024)
        return 501;
    /*verifier que c'est la bonne signature*/
    signer_IUM_2024(uminfs,nbligne-1,signature);
    if(strncmp(uminfs[nbligne-1],signature,TAILLE_SIGNATURE_2024)!=0)
        return 501;
    
    for(i=0;i<nbligne;i++)
    {
        if(uminfs[i]!=NULL)
            free(uminfs[i]);
    }
    return 0;
}

/*Fonction mfgets : lit une ligne d'un fichier ouvert en mode binaire
Cette fonction lit caract�re par caract�re le fichier en entr�e jusqu'� trouver le
premier caract�re de saut de ligne ('\n') ou de fin de ligne ('\r'), et
place l'ensemble de ces caract�res lus dans le buffer en sortie. Le curseur du fichier est ensuite positionn�
sur le premier caract�re non �gal � '\n' ou � '\r'.
*param�tres:
    buf : le buffer en sortie contenant la ligne lue.
    taillemax : la taille maximum du nombre de caract�res lus.
    ptrfile : pointeur sur le fichier ouvert en mode BINAIRE.
*valeur en retour : renvoie 0 si une erreur de lecture a eu lieu ou si la fin de fichier a
    �t� d�tect�e. Renvoie 1 si tout s'est bien pass�.
*/
int mfgets_2024(char *buf, int taillemax, FILE *ptrfile)
{
    int car,ret,crlf,fin,nbcar;
    ret=1;
    crlf=0;
    fin=0;
    nbcar=0;
    while(!fin)
    {
        car = fgetc(ptrfile);
        if(ferror(ptrfile))
        {
            ret = 0;
            break;
        }
        if(feof(ptrfile))
        {
            if(nbcar>0)
                ungetc(car,ptrfile);
            else
            {
                ret = 0;
            }
            break;
        }
        if(!crlf)
        {
            if((car == '\n') || (car == '\r'))
            {
                crlf=1;
            }
        }
        else
        {
            if((car != '\n') && (car != '\r'))
            {
                ungetc(car,ptrfile);
                break;
            }
        }
        if((car != '\n') && (car != '\r'))
        {
            if(nbcar>=taillemax)
            {
                ungetc(car,ptrfile);
                break;
            }
            buf[nbcar]=car;
            nbcar++;
        }
    }
    buf[nbcar] = 0;
    return ret;
}

int bChargeTableUM_2024(char sFic[])
{
	char buffer[51];
    int first;
    char umcourante[4];
    int indice;
    int i,j;
    int ret;

    indice_um$$$$_2024=-1;
	if(fptrum_2024!=NULL)
        return 0;
    if((fptrum_2024 = fopen(sFic,"r"))== NULL)
	{
		return(500);
	}
    memset(buffer,0,51);
	
    /*v�rification du fichier d'UM*/
    if((ret=verifFichierUMsigne_2024())!=0)
    {
        fclose(fptrum_2024);
        fptrum_2024=NULL;
        return ret;
    }
    
    memset(uminf_2024,0,MAX_UM_2024*sizeof(UMINFO_2024));
	for(i=0;i<MAX_UM_2024;i++)
    {
        for(j=0;j<MAX_TYPUM_2024;j++)
            uminf_2024[i].umdeclarees[j] = -1;
    }
    nbuminf_2024=0;
    first=1;
    fseek(fptrum_2024,0,SEEK_SET);
	while(mfgets_2024(buffer,50,fptrum_2024)!=0)
	{
		if(strlen(buffer)!=TAILLE_LIGNE_UM_2024)
            continue;
        if(first || (strncmp(buffer,umcourante,4)!=0))
        {
            strncpy(umcourante,buffer,4);
            if(!first)
                nbuminf_2024++;
			first=0;
            if(nbuminf_2024==MAX_UM_2024)
            {
                fclose(fptrum_2024);
                fptrum_2024=NULL;
                return 501;
		    }
            strncpy(uminf_2024[nbuminf_2024].um,buffer,4);
            uminf_2024[nbuminf_2024].nbautorisations=1;
            
            indice = getindicetypUM_2024(buffer+FICUM_TYP_2024);
            uminf_2024[nbuminf_2024].umdeclarees[indice]=0;
            uminf_2024[nbuminf_2024].autorisations[0].typum = indice;
            uminf_2024[nbuminf_2024].autorisations[0].invalidee = 0;
            strncpy(uminf_2024[nbuminf_2024].autorisations[0].datdebeffet,buffer+FICUM_DATE_DEB_2024,8);
            strncpy(uminf_2024[nbuminf_2024].autorisations[0].datfineffet,buffer+FICUM_DATE_FIN_2024,8);
            strncpy(uminf_2024[nbuminf_2024].autorisations[0].finessgeo,buffer+FICUM_FINESSGEO_2024,9);

            uminf_2024[nbuminf_2024].autorisations[0].troisemecartypum=*(buffer+FICUM_TYP_2024+2);
            uminf_2024[nbuminf_2024].autorisations[0].typhospit=*(buffer+FICUM_TYPHOSPIT_2024);

            /*CD FG13*/
            if(strncmp(uminf_2024[nbuminf_2024].um,"$$$$",4)==0)
                indice_um$$$$_2024=nbuminf_2024;
        }
        else
        {
            if(uminf_2024[nbuminf_2024].nbautorisations==MAX_AUTORISATIONS_UM_2024)
            {
			    fclose(fptrum_2024);
                fptrum_2024=NULL;
                return 501;
		    }
            indice = getindicetypUM_2024(buffer+FICUM_TYP_2024);
            if(uminf_2024[nbuminf_2024].umdeclarees[indice]==-1)
                uminf_2024[nbuminf_2024].umdeclarees[indice]=uminf_2024[nbuminf_2024].nbautorisations;
            uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].typum = indice;
            uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].invalidee = 0;
            strncpy(uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].datdebeffet,buffer+FICUM_DATE_DEB_2024,8);
            strncpy(uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].datfineffet,buffer+FICUM_DATE_FIN_2024,8);
            strncpy(uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].finessgeo,buffer+FICUM_FINESSGEO_2024,9);
            
            uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].troisemecartypum=*(buffer+FICUM_TYP_2024+2);
            uminf_2024[nbuminf_2024].autorisations[uminf_2024[nbuminf_2024].nbautorisations].typhospit=*(buffer+FICUM_TYPHOSPIT_2024);

            uminf_2024[nbuminf_2024].nbautorisations++;
        }
	}
	if(!first)
        nbuminf_2024++;
	return 0;
}

int estdeclare_2024(int indum, int typdum)
{
    return (uminf_2024[indum].umdeclarees[typdum] > -1);
}

int premierindiceTypUM_2024(int indum, int typdum)
{
    return (uminf_2024[indum].umdeclarees[typdum]);
}

int intersection_intervalles_2024(char *datedeb1, char *datefin1, char *datedeb2, char *datefin2, char **intersect1, char **intersect2)
{
	if (intersect1 == NULL)
		return 0;
	if (intersect2 == NULL)
		return 0;

	if (date_strict_sup_2024(datedeb1, datefin2))
		return 0;
	if (date_strict_sup_2024(datedeb2, datefin1))
		return 0;

	if (date_strict_sup_2024(datedeb2, datedeb1))
		*intersect1 = datedeb2;
	else
		*intersect1 = datedeb1;

	if (date_strict_sup_2024(datefin2, datefin1))
		*intersect2 = datefin1;
	else
	{
		*intersect2 = datefin2;
	}
	return 1;
}


int interval_autorise_2024(char datedebutdeffet[], char datefindeffet[], char date_entree[], char date_sortie[], int *nbjours)
{
    char *dateinf;
    char *datesup;

    if(nbjours)
        *nbjours=0;
    
    if(date_strict_sup_2024(datedebutdeffet,date_sortie))
        return 0;
    if(date_strict_sup_2024(date_entree,datefindeffet))
        return 0;
    
    if(date_strict_sup_2024(date_entree,datedebutdeffet))
        dateinf = date_entree;
    else
        dateinf = datedebutdeffet;
    
    if(date_strict_sup_2024(date_sortie,datefindeffet))
        datesup = datefindeffet;
    else
    {
        datesup = date_sortie;
    }

    if(nbjours)
        *nbjours = callos_2024(dateinf,datesup)+1;
    return 1;
}

int interval_autorise_hist_2024(char datedebutdeffet[], char datefindeffet[], char date_entree[], char date_sortie[], char** date_debfinale,char** date_finfinale,int *nbjours)
{
    char *dateinf;
    char *datesup;

    if(nbjours)
        *nbjours=0;
    
    if(date_strict_sup_2024(datedebutdeffet,date_sortie))
        return 0;
    if(date_strict_sup_2024(date_entree,datefindeffet))
        return 0;
    
    if(date_strict_sup_2024(date_entree,datedebutdeffet))
        dateinf = date_entree;
    else
        dateinf = datedebutdeffet;
    
    if(date_strict_sup_2024(date_sortie,datefindeffet))
        datesup = datefindeffet;
    else
    {
        datesup = date_sortie;
    }

    if(nbjours)
        *nbjours = callos_2024(dateinf,datesup)+1;
    *date_debfinale = dateinf;
    *date_finfinale = datesup;
    return 1;
}


/*teste si l'autorisatoin au niveau geographique est autoris�e au moins 1 jour dans l'intervalle de temps [d1,d2] pour le finess Geo */
int finessGeoAutorise_2024(char *pfinessgeo, int autorisationGeo, char *d1, char *d2)
{
	UMINFO_2024 luminfspec;
	int indumspec,i;
	char *d3, *d4;
	/*test si le type d'autorisation est global au finess geo*/
	if (umrefs_2024.typeportee[autorisationGeo] != 1)
		return 0;
	indumspec = indice_um$$$$_2024;
	if (indumspec<0)
		return 0;
	if (!estdeclare_2024(indumspec, autorisationGeo))
		return 0;
	luminfspec = uminf_2024[indumspec];
	i = premierindiceTypUM_2024(indumspec, autorisationGeo);
	d3 = d4 = 0;

	while ((i < luminfspec.nbautorisations) && (luminfspec.autorisations[i].typum == autorisationGeo))
	{
		if (strncmp(luminfspec.autorisations[i].finessgeo, pfinessgeo, 9) == 0)
		{
			if (intersection_intervalles_2024(luminfspec.autorisations[i].datdebeffet, luminfspec.autorisations[i].datfineffet, d1, d2, &d3, &d4))
				return 1;
		}
		i++;
	}
	return 0;
}

/*teste si une plage de temps [date_entree,date_sortie] est autoris�e en au moins 1 jour en type "typdum"
Renvoie 1 si oui, 0 sinon
Si oui, renvoie �galement le nombre de jours autoris�s, renvoie aussi un indicateur "bPremJourAutor"
pour savoir si le jour de la date d'entr�e est autoris� (si oui=1, 0 sinon)
*/
int est_autorise_2024(int indum, int typdum, char date_entree[], char date_sortie[], int *nbjours, int *bPremJourAutor)
{
    UMINFO_2024 luminf;
    int nbjinterv,i;
    int ret;
	char *d1, *d2;

	if(nbjours)
        *nbjours=0;
    else
        return 0;
    
    if(bPremJourAutor)
        *bPremJourAutor=0;
    else
        return 0;

    if(indum<0)
        return 0;
	i = 0;
	if (umrefs_2024.typeportee[typdum] != 1)
	{
		if (!estdeclare_2024(indum, typdum))
			return 0;
		i = premierindiceTypUM_2024(indum, typdum);
	}

	luminf = uminf_2024[indum];
	ret=0;
	d1 = d2 = 0;
	/*while ((i<luminf.nbautorisations) && (luminf.autorisations[i].typum == typdum))*/
	while (i<luminf.nbautorisations)
    {
		if (umrefs_2024.typeportee[typdum] != 1)
		{

			if (interval_autorise_2024(luminf.autorisations[i].datdebeffet, luminf.autorisations[i].datfineffet, date_entree, date_sortie, &nbjinterv))
			{
				*nbjours = *nbjours + nbjinterv;
				ret = 1;

				/*date d'entr�e autoris�e ?*/
				if (bPremJourAutor)
				{
					if ((!date_strict_sup_2024(luminf.autorisations[i].datdebeffet, date_entree)) && (!date_strict_sup_2024(date_entree, luminf.autorisations[i].datfineffet)))
						*bPremJourAutor = 1;
				}
			}
			i++;
			if ((i >= luminf.nbautorisations) || (luminf.autorisations[i].typum != typdum))
				break;
		}
		else
		{
			/*2017 autorisation globale signifie globale � un finess geo donn�*/
			d1 = d2 = 0;
			if (intersection_intervalles_2024(luminf.autorisations[i].datdebeffet, luminf.autorisations[i].datfineffet, date_entree, date_sortie,&d1,&d2))
			{
				/*tester si le finess geo est autoris� en ioa pendant l'intervalle de temps defini par l'intervalle de temps [d1,d2]*/
				if (finessGeoAutorise_2024(luminf.autorisations[i].finessgeo,typdum, d1, d2))
					return 1;
			}
			i++;
		}
    }
	return ret;
}


int nbjours_mois_2024(int mois, int annee)
{
  int nbj;
  switch (mois)
	{
		 case 1:
		 case 3:
		 case 5:
		 case 7:
		 case 8:
		 case 10:
		 case 12: nbj = 31; break;
		 case 4:
		 case 6:
		 case 9:
		 case 11: nbj = 30; break;
		 case 2: if (((annee%4 == 0) && (annee%100 !=0)) || (annee%400==0))
                     nbj=29;
				 else
					 nbj = 28;
				break;
		 default : nbj=0;
	}
  return nbj;
}

/*ajoute nbj nombre de jours � une date donn�e*/
void Ajout_jour_date_2024(char date[],int nbj,int *jour,int *mois,int *annee)
{
	int jj,mm,aa;

	convdate_2024 (date,&jj,&mm,&aa);
	while (nbj+jj>nbjours_mois_2024(mm,aa))
	{
		nbj=nbj-(nbjours_mois_2024(mm,aa)-jj+1);
		jj=1;
		if (mm==12)
    	{
			mm=1;
			aa++;
		}
		else
		{
			mm++;
		}
    }
	jj = jj+nbj;
	*jour = jj; *mois = mm; *annee = aa;
}
void Soustraire_jour_date_2024(char *date,int nbj,int *jour,int *mois,int *annee)
{
	int jj,mm,aa;

	convdate_2024 (date,&jj,&mm,&aa);
    if(nbj<0)
        nbj=0;
	while (jj-nbj<1)
	{
        nbj=nbj-jj;
        if(mm==1)
        {
            mm=12;
            aa--;
        }
        else
        {
            mm--;
        }
        jj=nbjours_mois_2024(mm,aa);
    }
	jj = jj-nbj;
	*jour = jj; *mois = mm; *annee = aa;
}



/* Retourne le type d'UM � une date donn�e*/
int trouveTypeUM_2024(char date[],int indum,int *typdum)
{
	int i;
	UMINFO_2024 luminf;
    if(indum<0)
        return 0;
    luminf = uminf_2024[indum];
	i=0;
	while ((i<luminf.nbautorisations) && (date_strict_sup_2024(date,luminf.autorisations[i].datfineffet) ||  date_strict_sup_2024(luminf.autorisations[i].datdebeffet,date)))
    {
		i++;
	}
	if (i>=luminf.nbautorisations)
		return 0;
	*typdum=luminf.autorisations[i].typum;
	return 1;
}

int trouveindiceUM_2024(char strUM[])
{
    int i,j;
	char trim_um[5];

	trim_um[4]=0;
	strncpy(trim_um,"    ",4);

	j=0;
	while((j<4) && (strUM[j]==' '))
		j++;
	if(j<4)
		strncpy(trim_um,&(strUM[j]),4-j);
	for(i=0;i<nbuminf_2024;i++)
	{
		if(strncmp(uminf_2024[i].um,trim_um,4)==0)
		{
			return i;
		}
	}
	return -1; /*l'UM n'existe pas dans le fichier d'UM*/
}

/*L'autorisation d'UM est elle dans REF_AUTO (d�pendant de la date de sortie du s�jour)*/
int autorisation_valide_2024(int ptypum)
{
    if(ptypum==TYPUM_BLANC)
        return 1;
    return umrefs_2024.bvalide[ptypum];
}
int autlitdedie_valide_2024(int ptyplitded)
{
    return litdedref_2024.bvalide[ptyplitded];
}
int getnumfoncsupplement_2024(int ptypum)
{
    return umrefs_2024.numfoncval[ptypum];
}
void getPlagesValo_2024(intervallesAutor_2024 **lesPlagesValo)
{
    *lesPlagesValo=plagesAutor_2024;
}

