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

// Global variable definitions (declared as extern in gestionUM2025.h)
FILE *fptrum_2025;
UMINFO_2025 uminf_2025[MAX_UM_2025];
int nbuminf_2025;
int indice_ums_2025[tab_max];
int indice_um$$$$_2025;
autref_2025 umrefs_2025;
autref_2025 litdedref_2025;
intervallesAutor_2025 plagesAutor_2025[tab_max];

#define CRC32_POLY_2025 0x04c11db7
unsigned long crc32_table_2025[256];

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

void init_crc32_2025()
{
	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_2025 : (c << 1);
		crc32_table_2025[i] = c;
	}
	
}
void signer_IUM_2025(unsigned char *buf[], int nbium,unsigned char *res)
{
	unsigned char *p;
	unsigned long  crc;
	int i,len;
    static int initcrc32_2025 = 0;
	    
    if(!initcrc32_2025)
    {
        init_crc32_2025();
        initcrc32_2025=1;
    }
    
	crc = 0xffffffff;
	
	for(i=0;i<nbium;i++)
	{	    
		p=buf[i];
		if(p == NULL) {
		    printf("ERROR: Buffer %d is NULL\n", i);
		    return;
		}
		
		len=strlen(p);
		
		for (p; len > 0; ++p, --len) {
            // IMPORTANT: We changed the initial implementation 
            // crc = (crc << 8) ^ crc32_table_2025[(crc >> 24) ^ ToAscii_2025(*p)];
		    if(p == NULL) {
		        printf("ERROR: p became NULL during character loop\n");
		        return;
		    }
		    crc = (crc << 8) ^ crc32_table_2025[((crc >> 24) & 0xFF) ^ ToAscii_2025((unsigned char)*p)];
		}
	}
	
	sprintf (res, "%010u",~crc);
}
int verifFichierUMsigne_2025()
{
    int eof;
    char buf[101];
    char buf2[101];
    int i,t;
    unsigned char signature[TAILLE_SIGNATURE_2025+1];
    int lgligne,nbligne;
    char *uminfs[MAX_LIGNE_UM_2025+1];
        
    eof=0;
    t=TAILLE_LIGNE_UM_2025;

    memset(buf,0,sizeof(buf));
    memset(buf2,0,sizeof(buf2));
    memset(uminfs,0,MAX_LIGNE_UM_2025+1);
    fseek(fptrum_2025,0,SEEK_SET);
    nbligne=0;
    
    while(!eof)
    {
        if(mfgets_2025(buf,100,fptrum_2025)==0)
        {
            eof=1;
            continue;
        }
        lgligne = strlen(buf);
        
        if(lgligne!=t)
        {
            strncpy(buf2,buf,lgligne);
            if(mfgets_2025(buf,100,fptrum_2025)!=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);
            
            if(uminfs[nbligne] == NULL) {
                printf("ERROR: Failed to allocate memory for signature line\n");
                return 501;
            }
            strncpy(uminfs[nbligne],buf2,lgligne);
            *(uminfs[nbligne]+lgligne)=0;
            nbligne++;
            eof=1;
        }
        else
        {
            uminfs[nbligne]=(char*)malloc(TAILLE_LIGNE_UM_2025+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_2025);
            *(uminfs[nbligne]+TAILLE_LIGNE_UM_2025)=0;
            nbligne++;
        }
    }
        
    if(nbligne<1)
    {
        printf("ERROR: No lines found, returning error\n");
        return 501;
    }
    
    /*verifier la taille de la signature*/
    if(strlen(uminfs[nbligne-1])!=TAILLE_SIGNATURE_2025)
    {
        printf("ERROR: Signature size mismatch\n");
        return 501;
    }
    
    /*verifier que c'est la bonne signature*/
    signer_IUM_2025(uminfs,nbligne-1,signature);
    
    if(strncmp(uminfs[nbligne-1],signature,TAILLE_SIGNATURE_2025)!=0)
    {
        printf("ERROR: Signature mismatch\n");
        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_2025(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_2025(char sFic[])
{
	char buffer[51];
    int first;
    char umcourante[4];
    int indice;
    int i,j;
    int ret;

    indice_um$$$$_2025=-1;
	if(fptrum_2025!=NULL)
        return 0;
    if((fptrum_2025 = fopen(sFic,"r"))== NULL)
	{
		return(500);
	}
    memset(buffer,0,51);
	
    /*vàrification du fichier d'UM*/
    if((ret=verifFichierUMsigne_2025())!=0)
    {
        fclose(fptrum_2025);
        fptrum_2025=NULL;
        return ret;
    }
    
    memset(uminf_2025,0,MAX_UM_2025*sizeof(UMINFO_2025));
	for(i=0;i<MAX_UM_2025;i++)
    {
        for(j=0;j<MAX_TYPUM_2025;j++)
            uminf_2025[i].umdeclarees[j] = -1;
    }
    nbuminf_2025=0;
    first=1;
    fseek(fptrum_2025,0,SEEK_SET);
	while(mfgets_2025(buffer,50,fptrum_2025)!=0)
	{
		if(strlen(buffer)!=TAILLE_LIGNE_UM_2025)
            continue;
        if(first || (strncmp(buffer,umcourante,4)!=0))
        {
            strncpy(umcourante,buffer,4);
            if(!first)
                nbuminf_2025++;
			first=0;
            if(nbuminf_2025==MAX_UM_2025)
            {
                fclose(fptrum_2025);
                fptrum_2025=NULL;
                return 501;
		    }
            strncpy(uminf_2025[nbuminf_2025].um,buffer,4);
            uminf_2025[nbuminf_2025].nbautorisations=1;
            
            indice = getindicetypUM_2025(buffer+FICUM_TYP_2025);
            uminf_2025[nbuminf_2025].umdeclarees[indice]=0;
            uminf_2025[nbuminf_2025].autorisations[0].typum = indice;
            uminf_2025[nbuminf_2025].autorisations[0].invalidee = 0;
            strncpy(uminf_2025[nbuminf_2025].autorisations[0].datdebeffet,buffer+FICUM_DATE_DEB_2025,8);
            strncpy(uminf_2025[nbuminf_2025].autorisations[0].datfineffet,buffer+FICUM_DATE_FIN_2025,8);
            strncpy(uminf_2025[nbuminf_2025].autorisations[0].finessgeo,buffer+FICUM_FINESSGEO_2025,9);

            uminf_2025[nbuminf_2025].autorisations[0].troisemecartypum=*(buffer+FICUM_TYP_2025+2);
            uminf_2025[nbuminf_2025].autorisations[0].typhospit=*(buffer+FICUM_TYPHOSPIT_2025);

            /*CD FG13*/
            if(strncmp(uminf_2025[nbuminf_2025].um,"$$$$",4)==0)
                indice_um$$$$_2025=nbuminf_2025;
        }
        else
        {
            if(uminf_2025[nbuminf_2025].nbautorisations==MAX_AUTORISATIONS_UM_2025)
            {
			    fclose(fptrum_2025);
                fptrum_2025=NULL;
                return 501;
		    }
            indice = getindicetypUM_2025(buffer+FICUM_TYP_2025);
            if(uminf_2025[nbuminf_2025].umdeclarees[indice]==-1)
                uminf_2025[nbuminf_2025].umdeclarees[indice]=uminf_2025[nbuminf_2025].nbautorisations;
            uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].typum = indice;
            uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].invalidee = 0;
            strncpy(uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].datdebeffet,buffer+FICUM_DATE_DEB_2025,8);
            strncpy(uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].datfineffet,buffer+FICUM_DATE_FIN_2025,8);
            strncpy(uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].finessgeo,buffer+FICUM_FINESSGEO_2025,9);
            
            uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].troisemecartypum=*(buffer+FICUM_TYP_2025+2);
            uminf_2025[nbuminf_2025].autorisations[uminf_2025[nbuminf_2025].nbautorisations].typhospit=*(buffer+FICUM_TYPHOSPIT_2025);

            uminf_2025[nbuminf_2025].nbautorisations++;
        }
	}
	if(!first)
        nbuminf_2025++;
	return 0;
}

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

int premierindiceTypUM_2025(int indum, int typdum)
{
    return (uminf_2025[indum].umdeclarees[typdum]);
}

int intersection_intervalles_2025(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_2025(datedeb1, datefin2))
		return 0;
	if (date_strict_sup_2025(datedeb2, datefin1))
		return 0;

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

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


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

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

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

int interval_autorise_hist_2025(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_2025(datedebutdeffet,date_sortie))
        return 0;
    if(date_strict_sup_2025(date_entree,datefindeffet))
        return 0;
    
    if(date_strict_sup_2025(date_entree,datedebutdeffet))
        dateinf = date_entree;
    else
        dateinf = datedebutdeffet;
    
    if(date_strict_sup_2025(date_sortie,datefindeffet))
        datesup = datefindeffet;
    else
    {
        datesup = date_sortie;
    }

    if(nbjours)
        *nbjours = callos_2025(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_2025(char *pfinessgeo, int autorisationGeo, char *d1, char *d2)
{
	UMINFO_2025 luminfspec;
	int indumspec,i;
	char *d3, *d4;
	/*test si le type d'autorisation est global au finess geo*/
	if (umrefs_2025.typeportee[autorisationGeo] != 1)
		return 0;
	indumspec = indice_um$$$$_2025;
	if (indumspec<0)
		return 0;
	if (!estdeclare_2025(indumspec, autorisationGeo))
		return 0;
	luminfspec = uminf_2025[indumspec];
	i = premierindiceTypUM_2025(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_2025(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_2025(int indum, int typdum, char date_entree[], char date_sortie[], int *nbjours, int *bPremJourAutor)
{
    UMINFO_2025 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_2025.typeportee[typdum] != 1)
	{
		if (!estdeclare_2025(indum, typdum))
			return 0;
		i = premierindiceTypUM_2025(indum, typdum);
	}

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

			if (interval_autorise_2025(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_2025(luminf.autorisations[i].datdebeffet, date_entree)) && (!date_strict_sup_2025(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_2025(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_2025(luminf.autorisations[i].finessgeo,typdum, d1, d2))
					return 1;
			}
			i++;
		}
    }
	return ret;
}


int nbjours_mois_2025(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_2025(char date[],int nbj,int *jour,int *mois,int *annee)
{
	int jj,mm,aa;

	convdate_2025 (date,&jj,&mm,&aa);
	while (nbj+jj>nbjours_mois_2025(mm,aa))
	{
		nbj=nbj-(nbjours_mois_2025(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_2025(char *date,int nbj,int *jour,int *mois,int *annee)
{
	int jj,mm,aa;

	convdate_2025 (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_2025(mm,aa);
    }
	jj = jj-nbj;
	*jour = jj; *mois = mm; *annee = aa;
}



/* Retourne le type d'UM à une date donnée*/
int trouveTypeUM_2025(char date[],int indum,int *typdum)
{
	int i;
	UMINFO_2025 luminf;
    if(indum<0)
        return 0;
    luminf = uminf_2025[indum];
	i=0;
	while ((i<luminf.nbautorisations) && (date_strict_sup_2025(date,luminf.autorisations[i].datfineffet) ||  date_strict_sup_2025(luminf.autorisations[i].datdebeffet,date)))
    {
		i++;
	}
	if (i>=luminf.nbautorisations)
		return 0;
	*typdum=luminf.autorisations[i].typum;
	return 1;
}

int trouveindiceUM_2025(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_2025;i++)
	{
		if(strncmp(uminf_2025[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_2025(int ptypum)
{
    if(ptypum==TYPUM_BLANC)
        return 1;
    return umrefs_2025.bvalide[ptypum];
}
int autlitdedie_valide_2025(int ptyplitded)
{
    return litdedref_2025.bvalide[ptyplitded];
}
int getnumfoncsupplement_2025(int ptypum)
{
    return umrefs_2025.numfoncval[ptypum];
}
void getPlagesValo_2025(intervallesAutor_2025 **lesPlagesValo)
{
    *lesPlagesValo=plagesAutor_2025;
}

