Page d'accueil Description du projet
/******************************************
 *
 *   Cedric Pradalier   2001
 *   mail : http://cedric.pradalier.free.fr/mail.html
 *
 *****************************************/



#include "output.h"
#include "lignes.h"
#include <string.h>
#include <stdlib.h>
#include "corresp.h"
/*****************************************************

  Implementation des lignes.


******************************************************/
//#define DEBUG

/* Initialisation physique */
CLignes::CLignes(char * rep,char * name,int i)
{
    mRep = (char *) malloc ((strlen(rep) + 1) * sizeof(char));
    strcpy(mRep,rep);
    mName = (char *) malloc ((strlen(name) + 1) * sizeof(char));
    strcpy(mName,name);
    mId = i;
    tArrets[s_aller]=tArrets[s_retour]=NULL;
    nArrets[s_aller]=nArrets[s_retour]=0;
    DonneesInterpol[s_aller] = NULL;
    DonneesInterpol[s_retour] = NULL;
}

/* On detruit tout */
CLignes::~CLignes()
{
    free(mName);
    free(mRep);
    delete [] tArrets[s_aller];
    delete [] tArrets[s_retour];
    delete [] DonneesInterpol[s_aller];
    delete [] DonneesInterpol[s_retour];
}


/* Lecture de toutes les donnees : Acces sequentiels a
   tous les fichiers. Attention a la syntaxe */
int CLignes::Read(CBDArrets * Liste)
{
    int s;
    char temp[100]="horaires/\0";
    char ext[] = "+-";
    int n;
    FILE * fp;
    strcat(temp,mRep);
    strcat(temp,"/arrets");
    n = strlen(temp);
    /* lecture de l'aller */
    strcat(temp," ");
    for(s=(int)s_aller;s<=(int)s_retour;s++)
    {
        temp[n] = ext[s];
        if ((fp = fopen(temp,"r")) == NULL)
        {
            sprintf(outbuf,"impossible de lire %s\n",temp);FlushBuffer();
            return 1;
        }
        else
        {
            fscanf(fp,"#arrets = %d \n",&nArrets[s]);
            tArrets[s] = new (CArrets*)[nArrets[s]];
            for (int i=0;i<nArrets[s];i++)
            {
                tArrets[s][i] = Liste->Find(tArrets[s][i]->ReadId(fp)); 
            }
            fclose(fp);
        }
    }   
    
    return 0;
}

/* Affichage standard : */
void CLignes::Print()
{
    int s;
    char * titres[2] = {"Aller","Retour"};
    sprintf(outbuf,"nom : %s\n",mName);FlushBuffer();
    sprintf(outbuf,"Id : %i\n",mId);FlushBuffer();
    for(s=(int)s_aller;s<=(int)s_retour;s++)
    {
        sprintf(outbuf,"Arrets : %s\n",titres[s]);FlushBuffer();
        for (int i=0;i<nArrets[s];i++)
            tArrets[s][i]->Print();
        sprintf(outbuf,"Horaires : %s\n",titres[s]);FlushBuffer();
        horaires[s].Print();
    }

}

/* Affichage minimum */
void CLignes::PrintMin()
{
    int s;
    char * titres[2] = {"Aller","Retour"};
    sprintf(outbuf,"nom : %s\n",mName);FlushBuffer();
    sprintf(outbuf,"Id : %i\n",mId);FlushBuffer();
    for(s=(int)s_aller;s<=(int)s_retour;s++)
    {
        sprintf(outbuf,"Arrets : %s\n",titres[s]);FlushBuffer();
        for (int i=0;i<nArrets[s];i++)
            tArrets[s][i]->PrintMin();
    }
}

/* Recherche du type d'horaire correspondant a une date D
 Acces sequentiel au fichier calendrier. Les periodes
 sont classees par priorite croissantes :
8 : Pas de bus ce jour la 
6 : Date
4 : Periode
2 : Jour de la semaine ( toute l'annee )
0 : Defaut 
 
Les date de validite du calendrier doivent etre correcte.
 */
TypeHoraire CLignes::FindTypeHoraire(CDate D)
{
    char temp[127] = "horaires/\0";
    strcat(temp,mRep);
    strcat(temp,"/calendrier");
    FILE * fp;
    if ((fp = fopen(temp,"r")) == NULL)
    {
        sprintf(outbuf,"impossible de lire %s\n",temp);FlushBuffer();
        return t_aucun;
    }
    Jours J = D.GetDayinWeek();
    CDate D1,D2;
    char ch;
    TypeHoraire Lu,Trouve = t_aucun;
    int Priorite_Trouve = -1;
    int i,j,n;
    /* Test de la periode de validite */
    fscanf(fp,"debut validite = ");
    D1.Read(fp);
    fscanf(fp," fin validite = ");
    D2.Read(fp);
    if (!D.IsBetween(D1,D2))
    {
        sprintf(outbuf,"Les horaires pour %s ne sont plus valides\n",mName);FlushBuffer();
        fclose(fp);
        return t_aucun;
    }
    /* Test dans toutes les periodes */
    for (i=0;i<5;i++)
    {
        /* Lecture : BLANC : n
           Ou n correspond au nombre de lignes a lire ensuite pour
           avoir toutes les donnees sur cette periode.
           si n = 0 : periode par defaut
           si n = -1 : Periode non utilisee
           sinon, on lit */
        fscanf(fp,"%s : %d \n",temp,&n);
        Lu = TypeofS(temp);
        if ((int)Lu == -1)
        {
            sprintf(outbuf,"Fichier calendrier pour %s invalide.\n",mName);FlushBuffer();
            fclose(fp);
            return t_aucun;
        }
        if (n<0)
            continue;
        else if ((n==0) && (Priorite_Trouve < 0))
        {
            Priorite_Trouve = 0;
            Trouve = Lu;
        }
        else
        /* Format des lignes :
           D <date>
        ou I <date_debut> <date_fin>
        ou J <Jour de la semaine>
        */
        for(j=0;j<n;j++)
        {
            fscanf(fp,"\t%c ",&ch);
            switch (ch)
            {
            case 'D' : {
                D1.Read(fp);
                fscanf(fp," \n");
                if ((Priorite_Trouve < 6) && (D1 == D))
                {
                    Priorite_Trouve = (Lu!=t_aucun)?6:8;
                    Trouve = Lu;
                }
                break;
                }
            case 'J' : {
                fscanf(fp,"%s \n",temp);
                if ((Priorite_Trouve < 4) && (J == GetDayofS(temp)))
                {
                    Priorite_Trouve = (Lu!=t_aucun)?4:8;
                    Trouve = Lu;
                }
                break;
                }
            case 'I' : {
                D1.Read(fp); fscanf(fp," ");
                D2.Read(fp); fscanf(fp," \n");
                if ((Priorite_Trouve < 2) && (D.IsBetween(D1,D2)))
                {
                    Priorite_Trouve = (Lu!=t_aucun)?2:8;
                    Trouve = Lu;
                }
                break;
                }
            }
        }
    }
    fclose(fp);
    return Trouve;

}




/* Lecture des horaires correspondant a un type d'horaire
   Blanc, orange... 
   La lecture en elle meme est laissee a la charge de la table
   d'horaire. Les donnees d'interpolation sont mises a jour
 */
void CLignes::LoadHoraires(TypeHoraire t,CBDArrets * liste)
{
    char temp[127] = "horaires/\0";
    int n;
    if (t == t_aucun)
        return;
    strcat(temp,mRep);
    strcat(temp,"/horaires");
    n=strlen(temp);
    strcat(temp,"+");
    strcat(temp,GetExtension(t));
    horaires[s_aller].Read(temp,liste);


    temp[n]=0;
    strcat(temp,"-");
    strcat(temp,GetExtension(t));
    horaires[s_retour].Read(temp,liste);

    UpdateInterpol ();
}


// renvoie l'indice (prive) d'un arret sur la ligne
int CLignes::Indice(SensTrajet s,CArrets * arret)
{
    int i=0;
    if (tArrets[s] == NULL)
    {
        i += 1;
    }
    while ((i<nArrets[s]) && (arret != tArrets[s][i]))
        i++;
    if (i<nArrets[s]) 
        return i;
    else
        return -1;
}
    
/* Test si un arret appartient a la ligne */
bool CLignes::IsKnown(CArrets * arret)
{
    return (Indice(s_aller,arret) > -1)
        || (Indice(s_retour,arret) > -1);
}

/* Test si on peut aller de l'arret From a l'arret Dest 
   sans changement */
bool CLignes::IsAccessible(CArrets * From,CArrets * Dest)
{
    int i;
    if (!IsUnique(From))
        return true; // D'un arret desservi dans les deux sens,
        // on peut acceder a tout autre arret (c'est un choix)
    bool FromTrouveAller = false;
    bool FromTrouveRetour = false;
    // On parcourt l'aller en esperant trouver From en premier
    // sinon, il n'est pas accessible dans ce sens
    for (i=0;i<nArrets[s_aller];i++)
    {
        if (tArrets[s_aller][i] == From)
            FromTrouveAller = true;
        if (tArrets[s_aller][i] == Dest)
            if (FromTrouveAller)
                return true;
            else
                break;
    }
    // Puis on repete dans l'autre sens. Ici, on peut sortir
    // directement.
    for (i=0;i<nArrets[s_retour];i++)
    {
        if (tArrets[s_retour][i] == From)
            FromTrouveRetour = true;
        if (tArrets[s_retour][i] == Dest)
            return FromTrouveRetour;
    }
    return false;
}
    
    

// renvoie le sens du trajet pour aller de depart a arrivee
// renvoie nonsens si depart ou arrivee ne sont pas sur cette ligne
SensTrajet CLignes::FindDirection(CArrets * depart,CArrets * arrivee)
{
    int i=0;
    int s;
    for (s=(int)s_aller;s<=(int)s_retour;s++)
    {
        for (i=0;i<nArrets[s];i++)
        {
            if (depart == tArrets[s][i])
                return (SensTrajet)s;
            if (arrivee == tArrets[s][i])
                return (SensTrajet) (1-s);
        }
    }
    return nonsens;
}



// Renvoie l'horaire de passage a l'arret 1
// Sachant qu'on veut etre a l'arret 2 avant
// l'horaire limite 
// renvoie HNULL en cas de Pb
CHoraire CLignes::Passage(CArrets * depart,CArrets * arrivee,CHoraire & limite)
{
    SensTrajet s;
    int trajet;
    int IndDepart,IndArrivee;
//  sprintf(outbuf,"On entre dans le passage (%s) ...\n",mName);FlushBuffer();
    if ((s=FindDirection(depart,arrivee)) == nonsens)
        return HNULL; // impossible de trouver depart ou arrivee
//  sprintf(outbuf,"Sens OK(%i) // cherchons le trajet...\n",s);FlushBuffer();
    if (((IndDepart = Indice(s,depart)) == -1) || ((IndArrivee = Indice(s,arrivee)) == -1))
        return HNULL;
//  sprintf(outbuf,"les arrets sont coherents.\n");FlushBuffer();
    if ((trajet = horaires[s].FindTrajet(IndArrivee,limite)) < 0)
        return HNULL; // arret introuvable ou pas d'horaire possible
//  sprintf(outbuf,"ce trajet (%i) est il possible ?\n",trajet);FlushBuffer();
    if ((trajet = horaires[s].FindFirstTrajetValid(trajet,IndDepart,IndArrivee)) < 0)
        return HNULL; // pas d'horaire possible
//  sprintf(outbuf,"Ya pus k interpoler le depart (%i)...\n",trajet);FlushBuffer();
    limite = horaires[s].Interpol(trajet,IndArrivee);
    return horaires[s].Interpol(trajet,IndDepart);
//  sprintf(outbuf,"Yaouuuuuu, ca a marche :)\n");FlushBuffer();
}

/* Mise a jour des donnees d'interpolation : 
   on a besoin pour chaque arret de savoir entre quelles arrets de 
   reference il se situe et sa position :
   0      1       2       3       4      5      6
   +------+-------+-------+-------+------+------+
   Rf2                    Arret A               Rf3

   Les donnees pour A sont
    Reference : 2
    NumeroArretInter = 3
    NbArretInter = 6
   On parcours tous les arrets sequentiellement
   en mettant ces donnees a jour
 */
   
void CLignes::UpdateInterpol()
{
    int last, Nb, i , j;
    InterPol temp = {0,1,0};
    int  s;
    
    for (s=(int)s_aller;s<=(int)s_retour;s++)
    {
        last = -1;Nb = 0;
        DonneesInterpol[s] = new InterPol[nArrets[s]];

        for (i=0;i<nArrets[s];i++)
        {
            temp.NumArretInter = 0xFF;
            DonneesInterpol[s][i] = temp;
        }
        for (i=0;i<horaires[s].NbArretRef;i++)
        {
            temp.NumArretInter = 0;
            DonneesInterpol[s][Indice((SensTrajet)s,horaires[s].tArretRef[i])] = temp;
        }
    //  sprintf(outbuf,"initialisation aller : \n");FlushBuffer();
        
        
        for (i=0;i<nArrets[s];i++,Nb++)
         if (DonneesInterpol[s][i].NumArretInter == 0)
         {
            for (j=0;j<Nb;j++)
            {
                temp.NumArretInter = j;
                temp.NumArretRef = last;
                temp.NbArretsInter = Nb;
                DonneesInterpol[s][i-Nb+j] = temp;
            }
            Nb = 0;
            last ++;
         }

        /* Cas particulier pour le dernier arret */
        temp.NumArretInter = 0;
        temp.NumArretRef = horaires[s].NbArretRef - 1;
        temp.NbArretsInter = 1;
        DonneesInterpol[s][nArrets[s]-1] = temp;

        /* Repercution des modif sur La table des horaires
           Son pointeur pointe sur le meme objet que celui de 
           la ligne */
        horaires[s].SetInterpol(DonneesInterpol[s]);
    }   
    
}

/* Lignes accessibles a partir d'un arret 
   Les correspondances possibles sont inserees dans l'ensemble
   E. Les lignes accessibles a partir de l'endroit ou on est
   ne sont pas prise en compte. En effet, si on veut prendre une
   autre ligne par cet arret, on ne passera pas par celle-ci.
   Parcours encore une fois sequentiel.
 */
void CLignes::LignesAccessibles(CEnsemble * E,CBDLignes * pBD,CCorresp * OuOnEst)
{
    CLignes * temp;
    CEnsemble * lignes = new CEnsemble();
    lignes->ajoute((CObjet*)this);
    int i,j,s;
    int Indic[2];
    int borneInf = 0;// L'aller
    int borneSup = 1;// Le retour
//  sprintf(outbuf,"Recherche des lignes accessibles\n");FlushBuffer();
    if ((Indic[s_aller] = Indice(s_aller,OuOnEst->arret)) == -1)
    {
        // On ne cherche pas sur l'aller, mais de toute facon, l'arret doit etre sur la ligne
        borneInf = 1;
    }
    
    if ((Indic[s_retour] = Indice(s_retour,OuOnEst->arret)) == -1)
    {
        // On ne cherche pas sur le retour, mais de toute facon, l'arret doit etre sur la ligne
        borneSup = 0;
    }
    for (s = borneInf ; s <= borneSup ; s++ )
    for (i = Indic[s] ; i < nArrets[s] ; i++)
        for (j=0;j<tArrets[s][i]->mNbLignesPresentes;j++)
        {
            if (tArrets[s][i]->mId != OuOnEst->arret->mId)
            {
                int l=tArrets[s][i]->tLignesPresentes[j];
//              sprintf(outbuf," %i",l);FlushBuffer();
                temp = pBD->Find(l);
                if ((temp != NULL) && 
                    (lignes->contains(temp) == -1))  
                {
//                  sprintf(outbuf,"OK");FlushBuffer();
                    CCorresp * nouveau = new CCorresp(tArrets[s][i],temp,(SensTrajet)s);
                    nouveau->precedent = OuOnEst;
                    E->ajoute((CObjet *)nouveau);
                    lignes->ajoute((CObjet *)temp);
                }
            }
        }
    delete lignes;
//  sprintf(outbuf,"\n");FlushBuffer();
}


/* Determine l'ensemble des arrets en sens unique 
   La liste des arrets dans les deux sens doit avoir ete
   lue auparavent */
void CLignes::FindSensUnique()
{
    int i_go,i_back;
    i_go = 0;
    i_back = nArrets[s_retour]-1;
    #ifdef DEBUG
    sprintf(outbuf,"Ligne étudiée : %s \n",mName);FlushBuffer();
    tArrets[s_aller][i_go]->Print();
    tArrets[s_retour][i_back]->Print();
    #endif
    while ((i_back >= 0) && (i_go < nArrets[s_aller] ))
    {
        if (tArrets[s_aller][i_go] == tArrets[s_retour][i_back])
        {
            i_go += 1;
            i_back -= 1;
        }
        else
        {
            #ifdef DEBUG
            sprintf(outbuf,"...?????./....???.\n");FlushBuffer();
            tArrets[s_aller][i_go]->Print();
            tArrets[s_retour][i_back]->Print();
            #endif
            if (Indice(s_aller,tArrets[s_retour][i_back]) == -1)
                if (Indice(s_retour,tArrets[s_aller][i_go]) == -1)
                {
                    ArretsUniques.ajoute((CObjet *) tArrets[s_aller][i_go]);
                    ArretsUniques.ajoute((CObjet *) tArrets[s_retour][i_back]);
                    i_go += 1;
                    i_back -= 1;
                }
                else
                {
                    ArretsUniques.ajoute((CObjet *) tArrets[s_retour][i_back]);
                    i_back -= 1;
                }
            else
                if (Indice(s_retour,tArrets[s_aller][i_go]) == -1)
                {
                    ArretsUniques.ajoute((CObjet *) tArrets[s_aller][i_go]);
                    i_go += 1;
                }
                else
                {
                    sprintf(outbuf,"Recherche des arrets uniques : situation absurde \n");FlushBuffer();
                    exit(0);
                }
        }
    }
    #ifdef DEBUG
    if (ArretsUniques.GetNbElem() == 0)
    {
        sprintf(outbuf,"Aucun arrets a sens unique\n");FlushBuffer();
    }
    else
    {
        sprintf(outbuf,"Arrets a sens uniques...\n");FlushBuffer();
        ArretsUniques.Print();
        sprintf(outbuf,"\n");FlushBuffer();
    }
    #endif
}


/* Test si un arret n'est desservi que dans un seul sens
   par cette ligne -- Utilisation de l'ensemble des arrets 
   en sens unique */
bool CLignes::IsUnique(CArrets * arret)
{
    return (ArretsUniques.contains(arret) != -1);
}