/* conseilcapo.c */
/* conseilcapo <SOURCE>
conseille une transposition pour que les accords soient plus simples */
/* gcc conseilcapo.c -std=gnu99 -o conseilcapo */

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

FILE *source;

int nbcases = 12;
int nbaccord = 24;

/* pour chq accord : s'il est barré(1) ou non */
int barre[24] = {0,1,1,0,1,0,1,0,1,1,0,1, 0,1,1,1,1,0,1,0,1,1,1,1};

/* pour chq accord : vrai ssi accord present */
int presence[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void aide()
{
  printf ("utilisation : conseilcapo <fichier source>\n");
}

void gestion_parametres (int nbarg, char **arg)
{
  /* vérification du nombre d'argument */
  if (nbarg != 2) 
    {
      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);
}

void av_car (int *carcour, int *ligne, int *colonne)
{
  if (*carcour == '\n')
    {
      (*ligne)++;
      *colonne = 1;
    }
  else
    {
      (*colonne)++;
    }
  *carcour = fgetc (source);
}

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

  etatcour = PAROLE;
  while (carcour != EOF)
    {
      switch (etatcour)
	{
	case PAROLE :
	  if (carcour == '[')
	    {
	      etatcour = ACCORDD;
	    }
	  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 ' ' : break;
	    case ']' : etatcour = PAROLE; break;
	    default : printf ("attention : l %d c %d: on attend un début d'accord et on a %c\n", ligne,colonne,carcour); etatcour = PAROLE;
	    }
	  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);
	    }
	  etatcour = ACCORDM2;

	case ACCORDM2 :
	  switch (carcour)
		{
		case 'm' : rang+=nbcases; av_car (&carcour, &ligne, &colonne); break;
		}
	  presence[rang] = 1;
	  etatcour = PAROLE;
	}
    }
}

void choisir_capo ()
{
  int min = nbaccord;
  int casecapofacile;
  /* pour chq case, difficuté */
  int difficulte[nbcases];

  for (int casecapo = 0 ; casecapo < nbcases ; casecapo++)
    {
      difficulte[casecapo] = 0;
    }
  /* trouver la difficulté de chq capo */
  for (int casecapo = 0 ; casecapo < nbcases ; casecapo++)
    {
      for (int accord = 0 ; accord < nbaccord ; accord++)
	{
	  if (presence[accord])
	    {
		  if (accord >= nbcases)
			{
			  difficulte[casecapo]+=barre[(accord-casecapo)%nbcases+nbcases];
			}
		  else
			{
			  difficulte[casecapo]+=barre[(accord-casecapo+nbcases)%nbcases];
			}
	    }
	}
    }

  /* trouver le min */
  for (int casecapo = 0 ; casecapo < nbcases ; casecapo++)
    {
      if (difficulte[casecapo] < min)
	{
	  min = difficulte[casecapo];
	  casecapofacile = casecapo;
       	}
    }
  printf ("conseil : mettre le capo en case %d (%d accord(s) barré(s))\n", casecapofacile, min);
  printf ("autres propositions :");
    for (int casecapo = 0 ; casecapo < nbcases ; casecapo++)
      {
	if (difficulte[casecapo] <= min+1 && casecapo != casecapofacile)
	  {
	    printf (" %d", casecapo);
	  }
      }
    printf("\n");
}

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

