static char rcsid[] = "$Id: grid.c,v 2.2 1992/08/27 18:24:53 putz Exp $";

#include "chord.h"

struct chord_struct chordtab[MAX_CHORD];
int    nb_chord;
int	first_ptr = 0;

/* char	known_chords[256][CHORD_NAME_SZ]; */
struct kcs {
	char	chord_name[CHORD_NAME_SZ];
	int	displ;
	int	s1,s2,s3,s4,s5,s6;
} known_chords[MAX_CHORD];


int	nb_known_chord = 0;

extern int hpos,vpos;
extern int grid_size;
extern char mesg[MAXTOKEN];

do_init_grid_ps()
{
	printf("%% routines for the drawing of the chords\n");
	printf("/grid { \n");
	printf("	gsave currentpoint\n");
	printf("	6 { 0 cagesizeX rlineto incr cagesize neg incr add rmoveto } repeat\n");
	printf("	moveto\n");
	printf("	5 { cagesize 0 rlineto 0 cagesize sub incr rmoveto } repeat\n");
	printf("	1 setlinewidth stroke grestore\n");
	printf("	gsave\n");
	printf("	0 cagesizeX rmoveto cagesize 0 rlineto\n");
	printf("	cagesize 30 div setlinewidth stroke\n");
	printf("	grestore	\n");
	printf("} def\n");
	printf("\n");
	printf("/dot {\n");
	printf("	gsave\n");
	printf("	/fret exch def /str exch def\n");
	printf("	/x 5  fret abs sub incr mul half-incr sub def\n");
	printf("	/y 6 str sub incr mul def\n");
	printf("	y x rmoveto\n");
	printf("	0 setgray\n");
	printf("	fret -1 eq\n");
	printf("	  {\n");
	printf("	  0 incr rmoveto\n");
	printf("	  check neg  check neg rmoveto\n");
	printf("	  check check rlineto check check rlineto\n");
	printf("	  check neg check neg rmoveto check neg check rmoveto\n");
	printf("  	  check check neg rlineto check check neg rlineto\n");
	printf("	  cagesize 50 div setlinewidth stroke\n");
	printf("	  }\n");
	printf("	  {  fret 0 ne\n");
	printf("	    { currentpoint dot-size 0 360 arc fill}\n");
	printf("	    { currentpoint\n");
	printf("	      check 0 360 newpath arc\n");
	printf("	      cagesize 50 div setlinewidth\n");
	printf("	    }\n");
	printf("	    ifelse \n");
	printf("	    stroke \n");
	printf("	  }\n");
	printf("	  ifelse\n");
	printf("	grestore\n");
	printf("} def	\n");
	printf("\n");
	printf("/dots {\n");
	printf("	grid\n");
	printf("	/fret-displ exch def\n");
	printf("	  1 1 6\n");
	printf("	  {\n");
	printf("	    /str exch def\n");
	printf("	    /fret exch def\n");
	printf("	    fret %d ne {str fret dot} if\n", FRET_NONE);
	printf("	  } for\n");
	printf("\n");
	printf("	fret-displ 1 ne\n");
	printf("	{\n");
	printf("    	  gsave\n");
	printf("    	  0 cagesize 3 div sub cagesizeX incr sub rmoveto\n");
	printf("    	  /char 1 string def fret-displ char cvs show grestore \n");
	printf("	} if\n");
	printf("\n");
	printf("	/chord-name exch def\n");
	printf("	gsave displ-font setfont\n");
	printf("	0 cagesizeX cagesizeX 15 div add dot-size 3 mul add rmoveto\n");
	printf("	chord-name stringwidth pop 2 div cagesize 2 div exch sub 0 rmoveto\n");
	printf("	chord-name show	chord-font setfont grestore\n");
	printf("} def\n");
	printf("\n");
	printf("/cagesize %d def\n",grid_size);
	printf("/incr cagesize 5 div def\n");
	printf("/cagesizeX incr 4 mul def\n");
	printf("/half-incr incr 2 div def\n");
	printf("/dot-size cagesize 15 div def\n");
	printf("/check cagesize 20 div def\n");
	printf("\n");
	printf("/chord-font /Times-Roman findfont cagesize 5 div scalefont def\n");
	printf("/displ-font /Times-Roman findfont cagesize 3 div scalefont def\n");
	printf("%% end of the routines for the drawing of the chords\n");
	printf("\n");
}


int add_to_chordtab(chord)
char *chord;
{
	int i, prev_i;
	int n;

/*  	fprintf(stderr, "attempting to add (%s)\n",chord); */
	i=first_ptr; prev_i = -1;
	while (1)
	{
/*		fprintf (stderr, "comparing with %d (%s)\n", i, chordtab[i].chord_name);  */
		if (nb_chord>0 && i != -1) {
			n=strcmp(chord, chordtab[i].chord_name);
			if (n==0)
				return(i);
			else if (n>0) {
				prev_i=i;
				i=chordtab[i].next_ptr;
				continue;
				}
			}
/* 		fprintf(stderr, "inserting between %d and %d\n",prev_i,i);  */

		strcpy(chordtab[nb_chord].chord_name,      chord);
		if (nb_chord!=0)
			chordtab[nb_chord].next_ptr=i;
		else
			chordtab[nb_chord].next_ptr = -1;
		if (prev_i != -1)
			chordtab[prev_i].next_ptr=nb_chord;
		if (i==first_ptr)
			first_ptr=nb_chord;
                if (nb_chord >= MAX_CHORD-1) {
		    fprintf(stderr, "too many chords, bumping %s\n",
			chordtab[nb_chord-1].chord_name);
		    return(nb_chord - 1);
		}
		nb_chord++;

/*
		fprintf(stderr, "dumping chordtab (start is %d)\n",first_ptr);
		for (i=0; i<nb_chord;i++) 
			fprintf(stderr, "	%d:	%10s -> %d\n",
				i,chordtab[i].chord_name,chordtab[i].next_ptr);
*/
		return(nb_chord - 1);
	}
}

moveto(new_hpos,new_vpos)
int	new_hpos,new_vpos;
{
	if (new_hpos + grid_size + L_MARGIN > WIDTH)
		{
		new_hpos = L_MARGIN;
		new_vpos -= 2*grid_size;
		}

	if (new_vpos < BOTTOM)
		{
		do_end_of_page();
		do_start_of_page();
		new_vpos=TOP-2*grid_size;
		}

	printf ("%d %d moveto\n", new_hpos, new_vpos);
	hpos=new_hpos;vpos = new_vpos;
}

draw_chords()
	{
	int ptr;
	int idx;

	moveto(WIDTH - grid_size - grid_size - L_MARGIN, vpos); 

	ptr=first_ptr;
	if (nb_chord != 0)
		{
		while (ptr != -1)
			{
			moveto(hpos + 2 * grid_size, vpos);

			if ((idx=is_chord_known(chordtab[ptr].chord_name))==-1)
				{
				sprintf (mesg, "chord \'%s\' has never been defined",
					chordtab[ptr].chord_name);
				error(mesg);

				printf("(%s) 0 0 0 0 0 0 1 dots\n",
					 chordtab[ptr].chord_name);
				}
			else
				printf("(%s) %d %d %d %d %d %d %d dots\n",
					known_chords[idx].chord_name,
					known_chords[idx].s1,
					known_chords[idx].s2,
					known_chords[idx].s3,
					known_chords[idx].s4,
					known_chords[idx].s5,
					known_chords[idx].s6,
					known_chords[idx].displ);
			ptr = chordtab[ptr].next_ptr;
	        	}
		}
	}

do_define_chord()
{
	int dot_array[6];
	char *chord_name;
	char *temp_str;
	int fret_displ;
	int n;
	int hardtoplay = 0;

	for ( n=0; n<6; n++)
		dot_array[n] = 0;

	chord_name=(char *)strtok(NULL, DELIM_STR);
	if (chord_name==NULL) {
		error("syntax error in chord definition: no chord name");
		return(0);
	}

	temp_str=(char *)strtok(NULL, DELIM_STR);
	if (temp_str==NULL) {
		error("syntax error in chord definition: no base fret position");
		return(0);
	}
	fret_displ=atoi(temp_str);

#ifdef DEBUGON
	fprintf(stderr, "fret_displ = %d\n", fret_displ);
#endif

	for (n=5; n>=0; n--)
		{
		temp_str=(char *)strtok(NULL, DELIM_STR);

#ifdef DEBUGON
		fprintf(stderr, "n = %d and temp_str = [%s]\n", n, temp_str);
#endif

		if (temp_str!=NULL) {
			if (!strcmp(temp_str, FRET_NONE_STR))
				dot_array[n]=FRET_NONE;
			else if (!strcasecmp(temp_str, FRET_X_STR))
				dot_array[n]=FRET_X;
			else {
				dot_array[n]=atoi(temp_str);
				if (dot_array[n] < 0) dot_array[n]=FRET_NONE;
			}
			hardtoplay=hardtoplay||(dot_array[n]>LONG_FINGERS);
			}
		else 
			{
			error("syntax error in chord definition : too few arguments");
			return(0);
			}
		}

	if (hardtoplay)
		{
		sprintf(mesg,
		  "Warning: You'll need long fingers to play \"%s\" this way!", chord_name);
		error (mesg);
		}

	learn_chord(chord_name,
			dot_array[0],dot_array[1],dot_array[2],
			dot_array[3],dot_array[4],dot_array[5],
			fret_displ);
}

learn_chord(chord, s1, s2, s3, s4, s5, s6, displ)
char 	*chord;
int	displ;
int	s1,s2,s3,s4,s5,s6;
{
        int i,not_found;

        not_found=TRUE;
        for (i=0;i < nb_known_chord && not_found; i++) {
                not_found=strcmp(chord,known_chords[i].chord_name);
        };

        if (not_found) {
                if (nb_known_chord >= MAX_CHORD-1) {
		    fprintf(stderr, "too many chords, can't learn %s\n", chord);
		    return(0);
		}
                nb_known_chord++;
		} else {
		i--;
		} 

        strcpy(known_chords[i].chord_name,chord);
	known_chords[i].displ=displ;
	known_chords[i].s1=s1;
	known_chords[i].s2=s2;
	known_chords[i].s3=s3;
	known_chords[i].s4=s4;
	known_chords[i].s5=s5;
	known_chords[i].s6=s6;

}

init_known_chords()
{
	nb_known_chord=0;

#define N FRET_NONE
#define X FRET_X
        learn_chord("Ab",     1,3,3,2,1,1,4);
        learn_chord("Abm",    1,3,3,1,1,1,4);	/* G#m is preferred */
        learn_chord("Ab7",    N,N,1,1,1,2,1);
        learn_chord("Abm7",   N,N,1,1,1,1,4);	/* G#m7 is preferred */
        learn_chord("Absus",  N,N,1,1,2,4,1);
        learn_chord("Ab+",    N,N,2,1,1,0,1);
        learn_chord("Abdim",  N,N,0,1,0,1,1);	/* G#dim is preferred */
        learn_chord("Abmaj7", N,N,1,1,1,3,1);


        learn_chord("A",      N,0,2,2,2,0,1);
        learn_chord("Am",     N,0,2,2,1,0,1);
        learn_chord("A7",     N,0,2,0,2,0,1);
        learn_chord("Am7",    N,0,2,2,1,3,1);
        learn_chord("Asus",   N,N,2,2,3,0,1);
        learn_chord("A+",     N,0,3,2,2,1,1);
        learn_chord("Adim",   N,N,1,2,1,2,1);
        learn_chord("Amaj7",  N,0,2,1,2,0,1);

        learn_chord("A#",     N,1,3,3,3,1,1);	/* Bb is preferred */
        learn_chord("A#m",    N,1,3,3,2,1,1);	/* Bbm is preferred */
        learn_chord("A#7",    N,N,1,1,1,2,3);	/* Bb7 is preferred */
        learn_chord("A#m7",   N,1,3,1,2,1,1);	/* Bbm7 is preferred */
        learn_chord("A#sus",  N,N,3,3,4,1,1);	/* Bbsus is preferred */
        learn_chord("A#+",    N,N,0,3,3,2,1);	/* Bb+ is preferred */
        learn_chord("A#dim",  N,N,2,3,2,3,1);	/* Bbdim is preferred */
        learn_chord("A#maj7", N,1,3,2,3,N,1);	/* Bbmaj7 is preferred */

        learn_chord("Bb",     N,1,3,3,3,1,1);
        learn_chord("Bbm",    N,1,3,3,2,1,1);
        learn_chord("Bb7",    N,N,1,1,1,2,3);
        learn_chord("Bbm7",   N,1,3,1,2,1,1);
        learn_chord("Bbsus",  N,N,3,3,4,1,1);
        learn_chord("Bb+",    N,N,0,3,3,2,1);
        learn_chord("Bbdim",  N,N,2,3,2,3,1);
        learn_chord("Bbmaj7", N,1,3,2,3,N,1);

        learn_chord("B",      N,2,4,4,4,2,1);
        learn_chord("Bm",     N,2,4,4,3,2,1);
        learn_chord("B7",     0,2,1,2,0,2,1);
        learn_chord("Bm7",    N,1,3,1,2,1,2);
        learn_chord("Bsus",   N,N,3,3,4,1,2);
        learn_chord("B+",     N,N,1,0,0,4,1);
        learn_chord("Bdim",   N,N,0,1,0,1,1);
        learn_chord("Bmaj7",  N,2,4,3,4,N,1);

        learn_chord("C",      N,3,2,0,1,0,1);
        learn_chord("Cm",     N,1,3,3,2,1,3);
        learn_chord("C7",     0,3,2,3,1,0,1);
        learn_chord("Cm7",    N,1,3,1,2,1,3);
        learn_chord("Csus",   N,N,3,0,1,3,1);
        learn_chord("C+",     N,N,2,1,1,0,1);
        learn_chord("Cdim",   N,N,1,2,1,2,1);
        learn_chord("Cmaj7",  N,3,2,0,0,0,1);

        learn_chord("C#",      N,N,3,1,2,1,1);	/* Db is preferred */
        learn_chord("C#m",     N,N,2,1,2,0,1);
        learn_chord("C#7",     N,N,3,4,2,4,1);	/* Db7 is preferred */
        learn_chord("C#m7",    N,N,2,4,2,4,1);
        learn_chord("C#sus",   N,N,3,3,4,1,4);	/* Dbsus is preferred */
        learn_chord("C#+",     N,N,3,2,2,1,1);	/* Db+ is preferred */
        learn_chord("C#dim",   N,N,2,3,2,3,1);
        learn_chord("C#maj7",  N,4,3,1,1,1,1);	/* Dbmaj7 is preferred */

        learn_chord("Db",      N,N,3,1,2,1,1);
        learn_chord("Dbm",     N,N,2,1,2,0,1);	/* C#m is preferred */
        learn_chord("Db7",     N,N,3,4,2,4,1);
        learn_chord("Dbm7",    N,N,2,4,2,4,1);	/* C#m7 is prefered */
        learn_chord("Dbsus",   N,N,3,3,4,1,4);
        learn_chord("Db+",     N,N,3,2,2,1,1);	/* Db+ is preferred */
        learn_chord("Dbdim",   N,N,2,3,2,3,1);
        learn_chord("Dbmaj7",  N,4,3,1,1,1,1);

        learn_chord("D",      N,N,0,2,3,2,1);
        learn_chord("Dm",     N,N,0,2,3,1,1);
        learn_chord("D7",     N,N,0,2,1,2,1);
        learn_chord("Dm7",    N,N,0,2,1,1,1);
        learn_chord("Dsus",   N,N,0,2,3,3,1);
        learn_chord("D+",     N,N,0,3,3,2,1);
        learn_chord("Ddim",   N,N,0,1,0,1,1);
        learn_chord("Dmaj7",  N,N,0,2,2,2,1);

        learn_chord("D#",      N,N,3,1,2,1,3);	/* Eb is preferred */
        learn_chord("D#m",     N,N,4,3,4,2,1);	/* Ebm is preferred */
        learn_chord("D#7",     N,N,1,3,2,3,1);	/* Eb7 is preferred */
        learn_chord("D#m7",    N,N,1,3,2,2,1);	/* Ebm7 is preferred */
        learn_chord("D#sus",   N,N,1,3,4,4,1);	/* Ebsus is preferred */
        learn_chord("D#+",     N,N,1,0,0,4,1);	/* Eb+ is preferred */
        learn_chord("D#dim",   N,N,1,2,1,2,1);
        learn_chord("D#maj7",  N,N,1,3,3,3,1);	/* Ebmaj7 is preferred */

        learn_chord("Eb",      N,N,3,1,2,1,3);
        learn_chord("Ebm",     N,N,4,3,4,2,1);
        learn_chord("Eb7",     N,N,1,3,2,3,1);
        learn_chord("Ebm7",    N,N,1,3,2,2,1);
        learn_chord("Ebsus",   N,N,1,3,4,4,1);
        learn_chord("Eb+",     N,N,1,0,0,4,1);
        learn_chord("Ebdim",   N,N,1,2,1,2,1);	/* D#dim is preferred */
        learn_chord("Ebmaj7",  N,N,1,3,3,3,1);

        learn_chord("E",      0,2,2,1,0,0,1);
        learn_chord("Em",     0,2,2,0,0,0,1);
        learn_chord("E7",     0,2,2,1,3,0,1);
        learn_chord("Em7",    0,2,2,0,3,0,1);
        learn_chord("Esus",   0,2,2,2,0,0,1);
        learn_chord("E+",     N,N,2,1,1,0,1);
        learn_chord("Edim",   N,N,2,3,2,3,1);
        learn_chord("Emaj7",  0,2,1,1,0,N,1);

        learn_chord("F",      1,3,3,2,1,1,1);
        learn_chord("Fm",     1,3,3,1,1,1,1);
        learn_chord("F7",     1,3,1,2,1,1,1);
        learn_chord("Fm7",    1,3,1,1,1,1,1);
        learn_chord("Fsus",   N,N,3,3,1,1,1);
        learn_chord("F+",     N,N,3,2,2,1,1);
        learn_chord("Fdim",   N,N,0,1,0,1,1);
        learn_chord("Fmaj7",  N,3,3,2,1,0,1);

        learn_chord("F#",     2,4,4,3,2,2,1);	/* or Gb */
        learn_chord("F#m",    2,4,4,2,2,2,1);	/* or Gbm */
        learn_chord("F#7",    N,N,4,3,2,0,1);	/* or Gb7 */
        learn_chord("F#m7",   N,N,2,2,2,2,1);	/* or Gbm7 */
        learn_chord("F#sus",  N,N,4,4,2,2,1);	/* or Gbsus */
        learn_chord("F#+",    N,N,4,3,3,2,1);	/* or Gb+ */
        learn_chord("F#dim",  N,N,1,2,1,2,1);	/* or Gbdim */
        learn_chord("F#maj7", N,N,4,3,2,1,1);	/* Gbdim is preferred */

        learn_chord("Gb",     2,4,4,3,2,2,1);	/* or F# */
        learn_chord("Gbm",    2,4,4,2,2,2,1);	/* or F#m */
        learn_chord("Gb7",    N,N,4,3,2,0,1);	/* or F#7 */
        learn_chord("Gbm7",   N,N,2,2,2,2,1);	/* or F#m7 */
        learn_chord("Gbsus",  N,N,4,4,2,2,1);	/* or F#sus */
        learn_chord("Gb+",    N,N,4,3,3,2,1);	/* or F#+ */
        learn_chord("Gbdim",  N,N,1,2,1,2,1);	/* or F#dim */
        learn_chord("Gbmaj7", N,N,4,3,2,1,1);

        learn_chord("G",      3,2,0,0,0,3,1);
        learn_chord("Gm",     1,3,3,1,1,1,3);
        learn_chord("G7",     3,2,0,0,0,1,1);
        learn_chord("Gm7",    1,3,1,1,1,1,3);
        learn_chord("Gsus",   N,N,0,0,1,3,1);
        learn_chord("G+",     N,N,1,0,0,4,1);
        learn_chord("Gdim",   N,N,2,3,2,3,1);
        learn_chord("Gmaj7",  N,N,1,2,3,4,2);

        learn_chord("G#",     1,3,3,2,1,1,4);	/* Ab is preferred */
        learn_chord("G#m",    1,3,3,1,1,1,4);
        learn_chord("G#7",    N,N,1,1,1,2,1);	/* Ab7 is preferred */
        learn_chord("G#m7",   N,N,1,1,1,1,4);
        learn_chord("G#sus",  N,N,1,1,2,4,1);	/* Absus is preferred */
        learn_chord("G#+",    N,N,2,1,1,0,1);	/* Ab+ is preferred */
        learn_chord("G#dim",  N,N,0,1,0,1,1);
        learn_chord("G#maj7", N,N,1,1,1,3,1);	/* Abmaj7 is preferred */
#undef N
#undef X
}

is_chord_known(chord)
char *chord;
{
        int i;

        for (i=0;i < nb_known_chord;i++)
                if (!strcmp(chord,known_chords[i].chord_name))
			return (i);
	return(-1);
}

dump_fret(fretnum)
{
	if (fretnum == FRET_NONE) printf("  %2s", FRET_NONE_STR);
	else if (fretnum == FRET_X) printf("  %2s", FRET_X_STR);
	else printf("  %2d", fretnum);
}

dump_chords()
{
	int i;

	printf ("#Chord		pos 1st 2nd 3rd 4th 5th 6th\n");
	for (i=0;i < nb_known_chord;i++) {
		printf("{define %s	%2d",
			known_chords[i].chord_name, known_chords[i].displ);
		dump_fret(known_chords[i].s6);
		dump_fret(known_chords[i].s5);
		dump_fret(known_chords[i].s4);
		dump_fret(known_chords[i].s3);
		dump_fret(known_chords[i].s2);
		dump_fret(known_chords[i].s1);
		printf("}\n");
	}
}
