/* transpose.c */
/* transpose <SOURCE> <DEST> <CAPO>
copie le fichier SOURCE dans le fichier DEST 
en transposant les accords de CAPO demi-tons 
vers les grâves */
/* gcc transpose.c -o transpose */
/* TODO : limiter les accords à 10 caractères, sinon erreur
   utiliser les fonctions approporiées pour donner ligne, colonne des erreurs */

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

FILE *source, *dest;

/* accords de ref dans l'ordre */
char accords[12][3] = {"A","Bb","B","C","C#","D","D#","E","F","F#","G","G#"};

int capo; /* on transpose de (capo) demi-tons */

void aide()
{
  printf ("utilisation : transpose <fichier source> <fichier destinataire> <case du capo>\n");
}

void gestion_parametres (int nbarg, char **arg)
{
  /* vérification du nombre d'argument */
  if (nbarg != 4) 
    {
      aide ();
      exit (1);
    }

  /* vérification et ouverture du fichier source */
  source = fopen (arg[1], "r");
  if (source == NULL) 
    {
      printf ("fichier source inconnu\n");
      exit (1);
    }
  rewind (source);

  /* vérification du paramètre de décalage */
  capo = atoi(arg[3]); 
  if (capo < -12 || capo > 12)
    {
      printf ("paramètre de transposition incorrect\n");
      exit(1);    
    }

  /* ouverture du fichier destinataire */
  dest = fopen (arg[2], "w");
}

void av_car (int *carcour, int *ligne, int *colonne)
{
  if (*carcour == 10) /* en ascii 10 <-> '/n' */
    {
      (*ligne)++;
      *colonne = 1;
    }
  else
    {
      (*colonne)++;
    }
  *carcour = fgetc (source);
}

void transp_fich ()
{
  int carcour = fgetc (source);
  int ligne = 1, colonne = 1;
  etat etatcour;
  int rang; /* défini l'accord (voir le tableau accords)*/
  int lg_acc_fin; /* longueur de la fin de l'accord */

  etatcour = PAROLE;
  while (carcour != EOF)
    {
      switch (etatcour)
	{
	case PAROLE :
	  if (carcour == '[')
	    {
	      etatcour = ACCORDD;
	    }
	  fputc (carcour, dest);
	  av_car (&carcour, &ligne, &colonne);
	  break;

	case ACCORDD :
	  switch (carcour)
	    {
	    case 'A' : rang = 0; etatcour = ACCORDM; break;
	    case 'B' : rang = 2; etatcour = ACCORDM; break;
	    case 'C' : rang = 3; etatcour = ACCORDM; break;
	    case 'D' : rang = 5; etatcour = ACCORDM; break;
	    case 'E' : rang = 7; etatcour = ACCORDM; break;
	    case 'F' : rang = 8; etatcour = ACCORDM; break;
	    case 'G' : rang = 10;etatcour = ACCORDM; break;
	    case '/' : 
	    case ' ' : fputc (carcour, dest); break;
	    case ']' : fputc (carcour, dest); etatcour = PAROLE; break;
	    default : printf ("erreur : l %d c %d: on attend un début d'accord et on a %c\n", ligne,colonne,carcour); exit(1);
	    }
	  av_car (&carcour, &ligne, &colonne);
	  break;

	case ACCORDM :
	  switch (carcour)
	    {
	    case '#' : rang++; av_car (&carcour, &ligne, &colonne); break;
	    case 'b' : rang--; av_car (&carcour, &ligne, &colonne);
	    }
	  fputs (accords[(rang-capo+12)%12], dest);
	  etatcour = ACCORDM2; lg_acc_fin = 0;
	  break;

	case ACCORDF :
	  if (lg_acc_fin > 10) /* sert à détecter les crochets non fermés */
	    {
	      printf ("attention : l %d c %d : est-ce vraiment un accord?\n", ligne, colonne);
	      etatcour = PAROLE;
	    }
	  switch (carcour)
	    {
	    case ']' : etatcour = PAROLE; break;
	    case '/' : etatcour = ACCORDD; break;
	    default : lg_acc_fin++;
	    }
	  fputc (carcour, dest);
	  av_car (&carcour, &ligne, &colonne);
	}
    }
}

int main(int argc, char *argv[])
{
  gestion_parametres (argc, argv);
  transp_fich ();
  fclose (source);
  fclose (dest);
  return 0;
}

