#include "squaredance.h"
#include "views.h"

#define TOTAL 40

static int checkDanceMusic( Dance *dance, char *filename ) {
    char musics[TOTAL][MUSICNAMELEN];
    int number[TOTAL];
    int barcnt[TOTAL];
    int last_music=-1;
    int last_music_bar=0;
    int lastbar=0 ;
    int has_conditional=false;
    int mcnt=0, i, j, val, ch, err=0;
    char *pt, *ept;

    memset( barcnt, 0, sizeof(barcnt) );
    for ( i=0; i<dance->call_cnt; lastbar += dance->calls[i].millibars, ++i ) {
	if ( dance->calls[i].part_mask!=0xffffffff )
	    has_conditional = true;
	
	pt = dance->calls[i].musicName;
	if ( *pt=='\0' )
    continue;
	ept = pt + strlen(pt)-1;
	while ( ept>pt && isdigit(*ept))
	    --ept;
	++ept;
	val = strtol(ept,NULL,10);
	ch = *ept;
	if ( last_music!=-1 && !has_conditional ) {
	    int bars = lastbar - last_music_bar;
	    if ( barcnt[last_music]==0 )
		barcnt[last_music] = bars;
	    else if ( barcnt[last_music]!= bars ) {
		fprintf( stderr, "%s: %s: Music %s sometimes has %d bars and other times %d.\n", filename, dance->name, musics[last_music], bars/1000, barcnt[last_music]/1000 );
		err=1;
	    }
	}
	last_music_bar = lastbar;
	if ( ch=='\0' ) {
/* This is OK if there are no further uses of this music */
#if 0
	    if ( strcasecmp(pt,"Intro")==0 || strcasecmp(pt,"Final")==0 )
		/* OK not to have a number */;
	    else {
		fprintf( stderr, "%s: Music %s has no number.\n", dance->name, pt );
		err = 1;
	    }
#endif
	} else if ( val==0 ) {
	    fprintf( stderr, "%s: %s: Music %s has number 0.\n", filename, dance->name, pt );
	    err = 1;
	} else if ( ch=='!' ) {
	    fprintf( stderr, "%s: %s: Music %s ends with a ! I think you meant 1.\n", filename, dance->name, pt );
	    err = 1;
	}
	if ( dance->calls[i].part_mask!=0xffffffff )
    continue;		/* Too hard to figure things out when we've got ifs */
	*ept = '\0';
	for ( j=0; j<mcnt; ++j ) {
	    if ( strcasecmp(pt,musics[j])==0 )
	break;
	}
	last_music = j;
	if ( j>=mcnt ) {
	    if ( val!=1 && val!=0 ) {
		fprintf( stderr, "%s: %s: Music %s%d must begin with 1.\n", filename, dance->name, pt, val );
		err = 1;
	    }
	    if ( mcnt<TOTAL ) {
		strcpy( musics[j],pt);
		number[j] = val;
		++mcnt;
	    } else {
		fprintf( stderr, "%s: %s: Too many different musics at: %s%d.\n", filename, dance->name, pt, val );
		err = 1;
	    }
	} else {
	    if ( val!=number[j]+1 ) {
		fprintf( stderr, "%s: %s: Music %s%d is a jump from %d.\n", filename, dance->name, pt, val, number[j] );
		err = 1;
	    }
	    number[j] = val;
	}
	*ept = ch;
    }
    if ( last_music!=-1 && !has_conditional ) {
	int bars = lastbar - last_music_bar;
	if ( barcnt[last_music]==0 )
	    barcnt[last_music] = bars;
	else if ( barcnt[last_music]!= bars ) {
	    fprintf( stderr, "%s: %s: Music %s sometimes has %d bars and other times %d.\n", filename, dance->name, musics[last_music], bars/1000, barcnt[last_music]/1000 );
	    err=1;
	}
    }
    for ( j=0; j<mcnt; ++j ) {
	if ( number[j]==1 ) {
	    fprintf( stderr, "%s: %s: Music %s1 has no number 2.\n", filename, dance->name, musics[j] );
	    err = 1;
	}
    }
return( err );
}

static void checkbars(Dance *dance) {
    int *tots, tot;
    int *counts;
    int part,i,j, top;
    int count, mosti, mostc;

    counts = calloc(dance->part_cnt*(dance->people+dance->role_cnt)+1,sizeof(int));
    for ( part=0; part<dance->part_cnt; ++part ) {
	if ( dance->role_cnt!=0 ) {
	    for ( i=0; i<dance->role_cnt; ++i ) {
		Person *p = &dance->roles[i];
		tot = blockCountMillibars(&p->figures);
#if 0
		for ( j=0, tot=0; j<p->figures.move_cnt; ++j )
		    if ( (p->figures.moves[j].part_mask & (1<<part)) &&
			    (p->figures.moves[j].condition==if_always ||
			     p->figures.moves[j].condition==if_nottopset ||
			     p->figures.moves[j].condition==if_notbottomset))
			tot += p->figures.moves[j].millibars;
#endif
		counts[part*dance->role_cnt + i] = tot;
	    }
	} else {
	    for ( i=0; i<dance->people; ++i ) {
		Person *p = &dance->dancers[i];
		tot = blockCountMillibars(&p->figures);
#if 0
		for ( j=0, tot=0; j<p->figures.move_cnt; ++j )
		    if ( p->figures.moves[j].part_mask & (1<<part))
			tot += p->figures.moves[j].millibars;
#endif
		counts[part*dance->people + i] = tot;
	    }
	}
    }
    tots = calloc(dance->part_cnt+1,sizeof(int));
    for ( part=0; part<dance->part_cnt; ++part ) {
	for ( j=0, tots[part]=0; j<dance->call_cnt; ++j ) {
	    if ( (dance->calls[j].part_mask&(1<<part)) || (dance->calls[j].part_mask&NOTLAST_MASK)) {
		tots[part] += dance->calls[j].millibars;
		if ( 1000*(dance->calls[j].millibars/1000) != dance->calls[j].millibars )
		    fprintf( stderr, "%s: Non-integral number of bars %.2f in call: %s.\n", dance->name, dance->calls[j].millibars/1000.0, dance->calls[j].callName );
	    }
	}
	if ( tots[part]!=tots[0] )
	    fprintf( stderr, "%s: The calls in part %d have a different length (%d) from those in part 1 (%d).\n",
		    dance->name, part+1, tots[part], tots[0] );
    }
    for ( j=0; j<dance->call_cnt; ++j ) {
	if ( dance->calls[j].millibars==0 &&
		dance->calls[j].callName!=NULL &&
		*dance->calls[j].callName!='\0' )
	    fprintf( stderr, "%s: the call '%s' is missing its bar argument.\n",
		    dance->name, dance->calls[j].callName );
    }
		
    

    top = dance->part_cnt*(dance->people+dance->role_cnt);
    mosti = -1; mostc=0;
    for ( i=0; i<top; ++i ) {
	count=0;
	for ( j=i; j<top; ++j )
	    if ( counts[i]==counts[j] ) ++count;
	if ( count>mostc ) {
	    mosti = i;
	    mostc = count;
	}
    }
    if ( counts[mosti]!=1000*(counts[mosti]/1000) )
	fprintf( stderr, "%s: Non-integral number of bars %.2f in the dancers' moves (%d).\n", dance->name, counts[mosti]/1000.0, mosti );
    if ( mostc==top ) {
	/* all roles have the same length */
	if ( tots[0]!=counts[0] && tots[0]!=0 )
	    fprintf( stderr, "%s: Different number of bars in the list of calls(%d) than in the dancers' moves(%d).\n", dance->name, tots[0], counts[0] );
	else
	    fprintf( stderr, "%s: Everything has the same number of bars: %.2f\n", dance->name, counts[0]/1000.0 );
return;
    }
    if ( mostc==top-1 ) {
	for ( i=0; i<top; ++i )
	    if ( counts[i]!=counts[mosti] )
	break;
	fprintf( stderr, "%s: All dancers except the %dth have %.3f bars, but the %dth have %.3f bars.\n",
		dance->name, i, counts[mosti]/1000.0, i, counts[i]/1000.0);
	if ( tots[0]!=0 ) {
	    if ( tots[0]==counts[mosti] )
		fprintf( stderr, "%s:  (the list of calls also has %.3f bars).\n", dance->name, tots[0]/1000.0 );
	    else if ( tots[0]==counts[i] )
		fprintf( stderr, "%s:  (the list of calls has the same number of bars as the odd dancer).\n", dance->name );
	    else
		fprintf( stderr, "%s:  (and the list of calls has a different number of bars: %.3f).\n", dance->name, tots[0]/1000.0 );
	}
return;
    }
    fprintf( stderr, "%s: Dancers %d", dance->name, mosti );
    for ( i=mosti+1; i<top; ++i )
	if ( counts[i]==counts[mosti] )
	    fprintf( stderr, ",%d", i );
    fprintf( stderr, " all have %.3f bars, while\n", counts[mosti]/1000.0 );
    for ( i=0; i<top; ++i )
	if ( counts[i]!=counts[mosti] )
	    fprintf( stderr, "%s:  dancer %d has %.3f bars.\n", dance->name, i, counts[i]/1000.0 );
    if ( tots[0]!=0 ) {
	if ( tots[0]==counts[mosti] )
	    fprintf( stderr, "%s:  the call list has the same number of bars as the most dancers: %.3f\n", dance->name, tots[0]/1000.0 );
	else
	    fprintf( stderr, "%s:  and the call list has %.3f bars.\n", dance->name, tots[0]/1000.0 );
    }

    /* now check that there are no hand clasps at impossible times */
    if ( dance->role_cnt!=0 ) {
	for ( i=0; i<dance->role_cnt; ++i ) {
	    Person *p = &dance->roles[i];
	    for ( j=0; j<p->figures.move_cnt; ++j ) {
		if ( p->figures.moves[j].drop_right_millibars!=HAND_MILLIBARS_UNSET &&
			p->figures.moves[j].drop_right_millibars > p->figures.moves[j].millibars )
		    fprintf( stderr, "%d: Dancer %d (role %s, sex %c) drops right hands after the spline ends on move %d lineno %d\n",
			    p->figures.moves[j].lineno, i, roleNames[p->effective_role], sexChars[p->sex] , j, p->figures.moves[j].lineno );
		if ( p->figures.moves[j].drop_left_millibars!=HAND_MILLIBARS_UNSET &&
			p->figures.moves[j].drop_left_millibars > p->figures.moves[j].millibars )
		    fprintf( stderr, "%d: Dancer %d (role %s, sex %c) drops left right hands after the spline ends on move %d lineno %d\n",
			    p->figures.moves[j].lineno, i, roleNames[p->effective_role], sexChars[p->sex] , j, p->figures.moves[j].lineno);
		if ( p->figures.moves[j].join_right_millibars!=HAND_MILLIBARS_UNSET &&
			p->figures.moves[j].join_right_millibars > p->figures.moves[j].millibars )
		    fprintf( stderr, "%d: Dancer %d (role %s, sex %c) joins right hands after the spline ends on move %d lineno %d\n",
			    p->figures.moves[j].lineno, i, roleNames[p->effective_role], sexChars[p->sex] , j, p->figures.moves[j].lineno);
		if ( p->figures.moves[j].join_left_millibars!=HAND_MILLIBARS_UNSET &&
			p->figures.moves[j].join_left_millibars > p->figures.moves[j].millibars )
		    fprintf( stderr, "%d: Dancer %d (role %s, sex %c) joins left right hands after the spline ends on move %d lineno %d\n",
			    p->figures.moves[j].lineno, i, roleNames[p->effective_role], sexChars[p->sex] , j, p->figures.moves[j].lineno);
	    }
	}
    } else {
	for ( i=0; i<dance->people; ++i ) {
	    Person *p = &dance->dancers[i];
	    for ( j=0; j<p->figures.move_cnt; ++j )
		fprintf( stderr, "This code isn't written yet, line %d of verify.c\n", __LINE__ );
	    counts[i] = tot;
	}
    }
return;
}

static void checkPersonEnd(Dance *dance, Person *p, int dancer_i) {
    int i, top;

    if ( p->figures.moves==NULL || p->figures.move_cnt==0 )
return;
    if ( p->figures.moves[p->figures.move_cnt-1].cmd != c_end && p->figures.moves[p->figures.move_cnt-1].cmd != c_resetDance )
	fprintf( stderr, "%s: Dancer %d's list of moves does not end with an end or reset command.\n", dance->name, dancer_i );

    top = p->figures.move_cnt-1;
    if ( p->figures.moves[top].cmd == c_end )
	--top;
    if ( top>0 && p->figures.moves[top].cmd == c_resetDance )
	--top;
    for ( i=0; i<top; ++i ) {
	if ( p->figures.moves[i].cmd==c_end || p->figures.moves[i].cmd==c_resetDance ) {
	    if ( i==p->figures.move_cnt-2 && p->figures.moves[i].cmd==c_end &&
		    p->figures.moves[i+1].cmd==c_resetDance )
		fprintf( stderr, "%s: Dancer %d has end command before reset command.\n", dance->name, dancer_i );
	    else if ( p->figures.moves[i].cmd==c_end )
		fprintf( stderr, "%s: Dancer %d has unexpected end command at index %d.\n", dance->name, dancer_i, i );
	    else
		fprintf( stderr, "%s: Dancer %d has unexpected reset command at index %d.\n", dance->name, dancer_i, i );
	}
    }
}

static void checkEnd(Dance *dance) {
    int i;

    if ( dance->role_cnt!=0 ) {
	for ( i=0; i<dance->role_cnt; ++i )
	    checkPersonEnd(dance,&dance->roles[i],i);
    } else {
	for ( i=0; i<dance->people; ++i )
	    checkPersonEnd(dance,&dance->dancers[i],i);
    }
}

static Position *endPosOfBlock(Block *b,Position *lastPos , Dance *dance,int dindex) {
    int i;

    for ( i=0; i<b->move_cnt; ++i ) {
	if ( b->moves[i].cmd==c_moveto || b->moves[i].cmd==c_lineto || b->moves[i].cmd==c_curveto )
	    lastPos = &b->moves[i].endPoint;
	else if ( b->moves[i].cmd==c_if ) {
	    Block *subb;
	    Position *anEnd = NULL, *temp;
	    for ( subb = b->moves[i].ifblock ; subb!=NULL ; subb=subb->next ) {
		temp = endPosOfBlock(subb,lastPos,dance,dindex);
		if ( temp==NULL )
		    /* Hmm. not sure how that could happen, but ignore for now */;
		else if ( anEnd==NULL )
		    anEnd = temp;
		else if ( temp->x!=anEnd->x || temp->y!=anEnd->y ) {
		    fprintf( stderr, "Two branches of an if end in different places, line %ld in %s for dancer %d.\n",
			    subb->lineno, dance->name, dindex );
		}
	    }
	    if ( anEnd!=NULL )
		lastPos = anEnd;
	}
	if ( i!=0 && b->moves[i].cmd==c_moveto )
	    fprintf( stderr, "%s: moveto command in middle of dance for dancer %d.\n", dance->name, dindex );
    }
return( lastPos );
}

static void checkPositions(Dance *dance) {
    /* This is to guard against rounding errors... something which should start */
    /* at 64, but is at 65 by mistake for instance */
    Person *p, *pbase, *pmax, *otherp;
    Position *lastPos;

    if ( dance->is_figure )
return;

    if ( dance->role_cnt!=0 ) {
	pbase = dance->roles;
	pmax = pbase + dance->role_cnt;
    } else {
	pbase = dance->dancers;
	pmax = pbase + dance->people;
    }
    for ( p=pbase ; p<pmax; ++p ) {
	if ( p->figures.move_cnt==0 ) {
	    fprintf( stderr, "%s: Dancer %d has no moves.\n", dance->name, (int) (p-pbase) );
return;
	}
	if ( p->figures.moves[0].cmd!=c_moveto ) {
	    fprintf( stderr, "%s: Dancer %d does not begin with a moveto.\n", dance->name, (int) (p-pbase) );
    continue;
	}
	for ( otherp=pbase; otherp<pmax; ++otherp ) if ( otherp!=p ) {
	    if ( otherp->figures.moves[0].endPoint.x==p->figures.moves[0].endPoint.x )
	break;
	}
	if ( otherp==pmax )
	    fprintf( stderr, "%s: The x start position of dancer %d does not match anyone's else start x.\n", dance->name, (int) (p-pbase) );
	for ( otherp=pbase; otherp<pmax; ++otherp ) if ( otherp!=p ) {
	    if ( otherp->figures.moves[0].endPoint.y==p->figures.moves[0].endPoint.y )
	break;
	}
	if ( otherp==pmax )
	    fprintf( stderr, "%s: The y start position of dancer %d does not match anyone's else start y.\n", dance->name, (int) (p-pbase) );
    }

    /* In everything but a Becket dance, all dancers must end the minor set */
    /*  where another dancer (possibly themselves) started */
    if ( dance->formation==sp_becket || dance->formation==sp_becketCCW || dance->formation==sp_shortWaves )

return;

    for ( p=pbase ; p<pmax; ++p ) {
	/* find where the dancer ends up */
	lastPos = NULL;
	lastPos = endPosOfBlock(&p->figures,NULL , dance,(int) (p-pbase));
	if ( lastPos==NULL )
	    fprintf( stderr, "%s: Dancer %d never positioned.\n", dance->name, (int) (p-pbase) );
	else {
	    for ( otherp=pbase; otherp<pmax; ++otherp ) {
		if ( otherp->figures.moves[0].endPoint.x == lastPos->x &&
			otherp->figures.moves[0].endPoint.y == lastPos->y )
	    break;
	    }
	    if ( otherp==pmax )
		fprintf( stderr, "%s: Dancer %d ends (%.1f,%.1f) where no other dancer starts.\n", dance->name, (int) (p-pbase), lastPos->x, lastPos->y );
	}
    }
}

static void fillClasps(int *clasps,Dance *dance) {
    int i;

    for ( i=0; i<dance->people; ++i ) {
	clasps[2*i+0] = dance->dancers[i].now_hand_right;
	clasps[2*i+1] = dance->dancers[i].now_hand_left;
    }
}

static int claspsDiffer(Dance *dance,int *clasps) {
    int i;

    for ( i=0; i<dance->people; ++i ) {
	/* It's ok to change normal clasp into a swing */
	if ( (clasps[2*i+0]&~HAND_BALLROOM_MASK) !=
		(dance->dancers[i].now_hand_right&~HAND_BALLROOM_MASK) )
return( true );
	if ( (clasps[2*i+1]&~HAND_BALLROOM_MASK) !=
		(dance->dancers[i].now_hand_left&~HAND_BALLROOM_MASK)  )
return( true );
    }
return( false );
}

static void checkHands(Dance *dance) {
    int f, i, other, other2, cnt;
    int frames_per_bar=8;
    int *clasps;
    int last_reset=0;
    /* I do this by instanciating the dance and running it through a few times*/
    /*  and checking that when person x thinks he's holding hands with person y*/
    /*  then person y agrees */

    if ( dance->roles!=NULL ) {
	int couples;
	if ( dance->formation==sp_fourFaceFour || dance->formation==sp_tempest || dance->formation==sp_quadrupleMinorBecket )
	    couples = 10;
	else if ( dance->formation==sp_scottishDupleMinor )
	    couples = 4;
	else if ( dance->formation==sp_scottishTripleMinor )
	    couples = 4;	/* could also be 7, 10, 13, ... */
	else if ( danceNeedsCoupleCount(dance) )
	    couples = 9;
	else
	    couples = dance->role_cnt/2;
	danceStart(dance,couples,0);
    }
    clasps = calloc(dance->people*2,sizeof(int));
    fillClasps(clasps,dance);

    for ( i=0; i<dance->people; ++i )
	printf( "%d: %s %c\n", i, roleNames[dance->dancers[i].effective_role], sexChars[dance->dancers[i].sex] );

    cnt = 0;
    if ( dance->people>0 &&
	(dance->dancers[0].figures.move_cnt==0 ||
	 dance->dancers[0].figures.moves[0].cmd==c_end ||
	 dance->dancers[0].figures.moves[0].cmd==c_resetDance ||
	 (dance->dancers[0].figures.move_cnt>0 &&
	  (dance->dancers[0].figures.moves[1].cmd==c_end ||
	   dance->dancers[0].figures.moves[1].cmd==c_resetDance))) )
	/* Do Nothing */;
    else for ( f=0; cnt<3; ++f ) {
	enum dancecondition dc;

	dc = danceNextFrame(dance,f,frames_per_bar);
	for ( i=0; i<dance->people; ++i ) {
	    if ( dance->dancers[i].join_right_without_drop!=0 ) {
		if ( dance->dancers[i].join_right_without_drop != (dance->dancers[i].now_hand_right&HAND_INDIVIDUAL_MASK) )
		    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) was holding someone's hand (%x) in his right when s/he was asked to join with another %x. %s\n",
			    dance->name, dance->dancers[i].current->lineno,
			    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role],
			    dance->dancers[i].join_right_without_drop, dance->dancers[i].now_hand_right,
			    (dance->current==NULL ) ? "" : dance->current->callName );
		dance->dancers[i].join_right_without_drop=0;
	    }
	    if ( dance->dancers[i].join_left_without_drop!=0 ) {
		if ( dance->dancers[i].join_left_without_drop != (dance->dancers[i].now_hand_left&HAND_INDIVIDUAL_MASK) )
		    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) was holding someone's hand (%x) in his left when s/he was asked to join with another %x. %s\n",
			    dance->name, dance->dancers[i].current->lineno,
			    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role],
			    dance->dancers[i].join_left_without_drop, dance->dancers[i].now_hand_left,
			    (dance->current==NULL ) ? "" : dance->current->callName );
		dance->dancers[i].join_left_without_drop=0;
	    }
	}
	if ( claspsDiffer(dance,clasps) ) {
	    fillClasps(clasps,dance);
	    for ( i=0; i<dance->people; ++i ) {
		if ( dance->dancers[i].now_hand_left!=0 ) {
		    other = dance->dancers[i].now_hand_left&HAND_INDIVIDUAL_MASK;
		    if ( other==HAND_STAR )
			/* That's ok */;
		    else if ( other>=dance->people ) {
			fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding left hands with someone outside the dance (%d). %s\n",
				dance->name, dance->dancers[i].current->lineno,
			        f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other,
			        dance->current==NULL ? "" : dance->current->callName );
		    } else {
			if ( dance->dancers[i].now_hand_left&HAND_RIGHT_MASK ) {
			    other2 = dance->dancers[other].now_hand_right;
			    if ( (other2&HAND_INDIVIDUAL_MASK)== i ) {
				if ( other2&HAND_LEFT_MASK )
				    /* That's correct! */;
				else
				    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) right hand in his left, but dancer %d thinks he's got hold of the right hand (correct person, wrong hand). %s\n",
					    dance->name, dance->dancers[i].current->lineno,
			                    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other,
					    dance->current==NULL ? "" : dance->current->callName );
			    } else if ( other2==0 ) {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) right hand in his left, but dancer %d thinks he's not holding anyone %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other&HAND_INDIVIDUAL_MASK].now_hand_left;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his left hand instead.\n",
					    other, i );
			    } else {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) right hand in his left, but dancer %d thinks he's got hold of someone else %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other&HAND_INDIVIDUAL_MASK].now_hand_left;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his left hand instead.\n",
					    other, i );
			    }
			} else if ( dance->dancers[i].now_hand_left&HAND_LEFT_MASK ) {
			    other2 = dance->dancers[other].now_hand_left;
			    if ( (other2&HAND_INDIVIDUAL_MASK)== i ) {
				if ( other2&HAND_LEFT_MASK )
				    /* That's correct! */;
				else
				    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's left hand in his left, but dancer %d thinks he's got hold of the right hand (correct person, wrong hand). %s\n",
					    dance->name, dance->dancers[i].current->lineno,
			                    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, other,
					    dance->current==NULL ? "" : dance->current->callName  );
			    } else if ( other2==0 ) {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) left hand in his left, but dancer %d thinks he's not holding anyone %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_right;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his right hand instead.\n",
					    other, i );
			    } else {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) left hand in his left, but dancer %d thinks he's got hold of someone else %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_right;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his right hand instead.\n",
					    other, i );
			    }
			} else
			    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding someone in his left hand, but he doesn't know which of the other guy's hands he is holding. %s\n",
				    dance->name, dance->dancers[i].current->lineno,
			            f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role],
					    dance->current==NULL ? "" : dance->current->callName  );
		    }
		}
		if ( dance->dancers[i].now_hand_right!=0 ) {
		    other = dance->dancers[i].now_hand_right&HAND_INDIVIDUAL_MASK;
		    if ( other==HAND_STAR )
			/* That's OK */;
		    else if ( other>=dance->people ) {
			fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding right hands with someone outside the dance (%d). %s\n",
				dance->name, dance->dancers[i].current->lineno,
			        f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other,
					    dance->current==NULL ? "" : dance->current->callName  );
		    } else {
			if ( dance->dancers[i].now_hand_right&HAND_RIGHT_MASK ) {
			    other2 = dance->dancers[other].now_hand_right;
			    if ( (other2&HAND_INDIVIDUAL_MASK)== i ) {
				if ( other2&HAND_RIGHT_MASK )
				    /* That's correct! */;
				else
				    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's right hand in his right, but dancer %d thinks he's got hold of the left hand (correct person, wrong hand). %s\n",
					    dance->name, dance->dancers[i].current->lineno,
			                    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, other,
					    dance->current==NULL ? "" : dance->current->callName  );
			    } else if ( other2==0 ) {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) right hand in his right, but dancer %d thinks he's not holding anyone %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_left;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his left hand instead.\n",
					    other, i );
			    } else {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) right hand in his right, but dancer %d thinks he's got hold of someone else %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other, other2&HAND_INDIVIDUAL_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_left;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his left hand instead.\n",
					    other, i );
			    }
			} else if ( dance->dancers[i].now_hand_right&HAND_LEFT_MASK ) {
			    other2 = dance->dancers[other].now_hand_left;
			    if ( (other2&HAND_INDIVIDUAL_MASK)== i ) {
				if ( other2&HAND_RIGHT_MASK )
				    /* That's correct! */;
				else
				    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) left hand in his right, but dancer %d thinks he's got hold of the right hand (correct person, wrong hand). %s\n",
					    dance->name, dance->dancers[i].current->lineno,
			                    f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other&HAND_INDIVIDUAL_MASK].effective_role], other,
					    dance->current==NULL ? "" : dance->current->callName  );
			    } else if ( other2==0 ) {
				fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding dancer %d's(%s) left hand in his right, but dancer %d thinks he's not holding anyone %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other].effective_role], other, other2&HAND_PERSON_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_right;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his right hand instead.\n",
					    other, i );
			    } else {
				fprintf( stderr, "%s:%d: At bar %.3f(%.3f), dancer %d(%s) believes he is holding dancer %d's(%s) left hand in his right, but dancer %d thinks he's got hold of someone else %x. %s\n",
					dance->name, dance->dancers[i].current->lineno,
			                f/(double) frames_per_bar, (f-last_reset)/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role], other, roleNames[dance->dancers[other].effective_role], other, other2&HAND_PERSON_MASK,
					    dance->current==NULL ? "" : dance->current->callName  );
				other2 = dance->dancers[other].now_hand_right;
				if ( (other2&HAND_INDIVIDUAL_MASK)== i )
				    fprintf( stderr, "\tAh, but %d believes he's got %d in his right hand instead.\n",
					    other, i );
			    }
			} else
			    fprintf( stderr, "%s:%d: At bar %.3f, dancer %d(%s) believes he is holding someone in his right hand, but he doesn't know which of the other guy's hands he is holding.\n",
				    dance->name, dance->dancers[i].current->lineno,
			            f/(double) frames_per_bar, i, roleNames[dance->dancers[i].effective_role] );
		    }
		}
	    }
	}

	if ( dc==dc_finished )
    break;
	else if ( dc==dc_minorSetEnded ) {
	    ++cnt;
	    last_reset = f;
	}
    }
    if ( dance->roles!=NULL )
	danceCleanup(dance);
}

static void ScottishChecks(Dance *dance) {
    char buffer[100];

    printf( "%s\n", danceScottishPrecis(buffer,sizeof(buffer), dance ));
    if ( dance->source_url!=NULL && strcmp(dance->source_url,"https://www.scottish-country-dancing-dictionary.com/dance-crib/")==0 ) {
	fprintf( stderr, "Incomplete source url.\n" );
    }
    if ( dance->style != ds_scottish )
return;

    if ( danceHasTag(dance,"medley") )
	/* Who knows what the counts per bar might be ?*/;
    else if ( danceHasTag(dance,"strathspey") ) {
	if ( dance->counts_per_bar!=4 )
	    fprintf( stderr, "Bad counts per bar for a strathspey. Must be 4.\n" );
    } else if ( danceHasTag(dance,"waltz") || danceHasTag(dance,"slip-jig")) {
	if ( dance->counts_per_bar!=3 )
	    fprintf( stderr, "Bad counts per bar for a waltz/slip-jig. Must be 3.\n" );
    } else if ( danceHasTag(dance,"reel") || danceHasTag(dance,"jig")) {
	if ( dance->counts_per_bar!=2 )
	    fprintf( stderr, "Bad counts per bar for a reel/jig. Must be 2.\n" );
    } else {
	fprintf( stderr, "No (known) music specified for a scottish dance.\n" );
    }
}

int main( int argc, char **argv) {
    int i, j, k;
    FigureLib *cl;

    if ( argc==1 ) {
	fprintf( stderr, "What did you want verified?.\n" );
exit( 1 );
    }
    for ( i=1; i<argc; ++i ) {
	cl = danceLoadLibrary(argv[i] );
	if ( cl==NULL ) {
	    fprintf( stderr, "Failed to load library file: %s\n", argv[i] );
	    fprintf( stderr, " %s\n", danceLoaderError());
	    if ( i+1<argc )
    continue;
	    else
exit( 1 );
	}
	ScottishChecks(cl->figures[0]);
	danceOutputLibraryInfo("fuf.dance",cl);
	if ( cl->figures!=NULL ) {
	    for ( j=0; cl->figures[j]!=NULL; ++j ) {
		Dance *d = cl->figures[j];
		if ( d->comp_cnt!=0 ) {
		    for ( k=0; k<d->comp_cnt; ++k ) {
			struct dance *cd = d->components[k];
			checkbars(cd);
			checkEnd(cd);
			checkPositions(cd);
			checkHands(cd);
			checkDanceMusic(cd,argv[i]);
			danceCheckCallLength(cd);
		    }
		} else {
		    checkbars(d);
		    checkEnd(d);
		    checkPositions(d);
		    checkHands(d);
		    checkDanceMusic(d,argv[i]);
		    danceCheckCallLength(d);
if (( d->formation<sp_dupleMinor || d->formation > sp_tripleMinor ) && d->formation!=sp_scottishDupleMinor && d->formation!=sp_scottishTripleMinor ) {
    struct setProgression sp; int i;

    danceSetProgression(d,&sp);
    printf( "(%d", sp.progression[0]+1 );
    for ( i=1; i<d->role_cnt/2; ++i )
	printf( ", %d", sp.progression[i]+1 );
    printf( ")\n" );
}
		}
	    }
	}
	figureLibFree(cl);
    }
return( 0 );
}
