#include <stdio.h>
#include <stdlib.h>
#include "reseau.h"

#define SOURCE 26
#define DESTINATION 42
#define MAXRETRANSMISSION 10
#define FEMISSION  "flux1.dat"
#define FRECEPTION "flux2.dat"

int erreurcrc=0;

void envoyer(ttrame Trame)
/* Envoie la trame Trame vers la couche physique en rajoutant si nécessaire des erreurs */
{
  if ((erreurcrc!=0) && ((rand() % erreurcrc)==0))
  {
    Trame.CRC++;
    envoyer_vers_couche_physique(Trame);
    Trame.CRC--;
  }
  else envoyer_vers_couche_physique(Trame);
  return;
}

char entre(int a, int b, int c)
{
  return( ((a<=b)&&(b<c)) || ((c<a)&&(a<=b)) || ((b<c)&&(c<a)) );
}

int main(int argc, char **argv)
/* Programme principal, argument optionnel : quantité d'erreurs */
{
  int AS,AD;
  ttrame buffer[MAXTAILLEFENETRE];
  int compteur[MAXTAILLEFENETRE];
  int i, numack, ack_attendu=0, trame_a_emettre=0, nbuffer=0;
  ttampon TamponEmission, tamponaux;
  ttrame Trame;
  char recepteur_pret=1;

  if (argc>1) erreurcrc=atoi(argv[1]);

  fprintf(stderr,"Initialisation du protocole 4, erreurcrc=%d\n",erreurcrc);
  initialise_couche_physique(FEMISSION, FRECEPTION);
  initialise_couche_reseau(SOURCE, DESTINATION);

  while (1)
  {
    if (recepteur_pret && signale(SIGEMIS) && (nbuffer<MAXTAILLEFENETRE-1))
    {
      prendre_de_la_couche_reseau(&AS, &AD, &TamponEmission);
      construire_trame(trame_a_emettre, AS, AD, TamponEmission, &buffer[trame_a_emettre]);
      nbuffer++;
      fprintf(stderr,"Envoi de trame %d : %d->%d, %s\n",trame_a_emettre,AS,AD,TamponEmission.info);
      envoyer(buffer[trame_a_emettre]);
      tempo(trame_a_emettre);
      compteur[trame_a_emettre]=MAXRETRANSMISSION;
      trame_a_emettre=(trame_a_emettre+1)%MAXTAILLEFENETRE;
    }
    if (signale(SIGTEMPO))
    {
      fprintf(stderr,"Timeout\n");
      trame_a_emettre=ack_attendu;
      for (i=0;i<nbuffer;i++)
      {
        if (compteur[trame_a_emettre]==0)
        {
          fprintf(stderr,"Trop d'erreurs de retransmission\n");
          return(1);
        }
        fprintf(stderr,"Renvoi de trame %d : %d->%d, %s\n",trame_a_emettre,AS,AD,buffer[trame_a_emettre].tampon.info);
        envoyer(buffer[trame_a_emettre]);
        tempo(trame_a_emettre);
        compteur[trame_a_emettre]--;
        trame_a_emettre=(trame_a_emettre+1)%MAXTAILLEFENETRE;
      }
    }
    if (signale(SIGRECU))
    {
      prendre_de_la_couche_physique(&Trame);
      recuperer_donnees(Trame,&tamponaux,&numack,&AS,&AD);
      fprintf(stderr,"ACK RECU %d, ACK ATTENDU %d, TRAME A EMETTRE %d\n",numack,ack_attendu,trame_a_emettre);
      while (entre(ack_attendu,numack,trame_a_emettre))
      {
        fprintf(stderr,"Trame %d acquitee\n",ack_attendu);
        nbuffer--;
        stoptempo(ack_attendu);
        ack_attendu=(ack_attendu+1)%MAXTAILLEFENETRE;
      }
      switch (tamponaux.info[0])
      {
        case 'R':{ if (recepteur_pret==0) fprintf(stderr,"RR recu\n"); recepteur_pret=1; break; }
        case 'N':{ recepteur_pret=0; fprintf(stderr,"RNR recu\n"); break; }
      }
    }
  }
  return(0);
}