#include "squaredance.h"
#include <assert.h>

static int peopleCntFromStartingPosition[] = {
	8,	/* sp_squaredSet, */
	12,	/* sp_rect6Set, */
	4,	/* sp_facingCouples, */
	2,	/* sp_facingPeople, */
	2,	/* sp_couple, */
	1,	/* sp_singleton, */
	4,	/* sp_rightHandWave, */
	4,	/* sp_leftHandWave, */
	8,	/* sp_2rightHandWave, */
	8,	/* sp_2leftHandWave, */
	8,	/* sp_dupleMinor, */
	8,	/* sp_becket, */
	8,	/* sp_becketCCW, */
	8,	/* sp_shortWaves, */
	8,	/* sp_dupleMinorProgressed, */
	12,	/* sp_threeFaceThree, */
	16,	/* sp_fourFaceFour, */
	16,	/* sp_tempest, */
	16,	/* sp_quadrupleMinorBecket, */
	12,	/* sp_tripleMinor, */
	4,	/* sp_2Couple, */
	6,	/* sp_3Couple, */
	8,	/* sp_4Couple, */
	10,	/* sp_5Couple, */
	12,	/* sp_6Couple, */
	14,	/* sp_7Couple, */
	16,	/* sp_8Couple, */

	6,	/* sp_3CplCircle, */
	/* A 4 couple circle is a square */
	10,	/* sp_5CplCircle, */
	12,	/* sp_6CplCircle, */
	14,	/* sp_7CplCircle, */

	12,	/* sp_square3, */

	8,	/* sp_scottishDupleMinor, */
	12,	/* sp_scottishTripleMinor, */

	12,	/* sp_circularMonopole, */
	12,	/* sp_trioCircularMonopole, */

	0,	/* sp_custom */
	0	/* sp_custom3 */
};

static void moveTo(Person *p, int x, int y, int facing ) {
    assert( p->figures.move_cnt==0 && p->figures.move_max>0 );
    p->now.x = x;
    p->now.y = y;
    p->now_orientation = facing;
    p->figures.moves[0].cmd     = c_moveto;
    p->figures.moves[0].degrees = facing;
    p->figures.moves[0].endPoint.x = x;
    p->figures.moves[0].endPoint.y = y;
    p->figures.move_cnt=1;
}

static void copyRolesMoveTo(Dance *dance,enum role to, enum role from) {
    Person *p, *r;
    int sex;

    for ( sex=sex_first; sex<sex_max; ++sex ) {
	p = danceFindRole(dance,to,sex);
	if ( p!=NULL ) {
	    r =danceFindRole(dance,from,sex);
	    if ( r==NULL ) {
		fprintf( stderr, "Could not find role to copy.\n" );
exit(1);
	    }
	    moveTo(p,r->figures.moves[0].endPoint.x,
		     r->figures.moves[0].endPoint.y,
		     r->figures.moves[0].degrees);
	}
    }
}

static void joinHandsDancers(Figure *figure,int hand1,int hand2) {
    int h1 = hand1&~(HAND_RIGHT_MASK|HAND_LEFT_MASK);
    int h2 = hand2&~(HAND_RIGHT_MASK|HAND_LEFT_MASK);

    assert(h1<figure->people);
    assert(h2<figure->people);
    assert( figure->dancers[h1].figures.move_cnt==1 );
    assert( figure->dancers[h2].figures.move_cnt==1 );
    if ( hand1&HAND_RIGHT_MASK )
	figure->dancers[h1].figures.moves[0].join_right_hand = hand2;
    else
	figure->dancers[h1].figures.moves[0].join_left_hand = hand2;
    if ( hand2&HAND_RIGHT_MASK )
	figure->dancers[h2].figures.moves[0].join_right_hand = hand1;
    else
	figure->dancers[h2].figures.moves[0].join_left_hand = hand1;
}

static void joinHandsRoles(Figure *figure,int hand1,int hand2) {
    int h1 = hand1&~(HAND_RIGHT_MASK|HAND_LEFT_MASK);
    int h2 = hand2&~(HAND_RIGHT_MASK|HAND_LEFT_MASK);

    assert(h1<figure->role_cnt);
    assert(h2<figure->role_cnt);
    assert( figure->roles[h1].figures.move_cnt==1 );
    assert( figure->roles[h2].figures.move_cnt==1 );
    if ( hand1&HAND_RIGHT_MASK )
	figure->roles[h1].figures.moves[0].join_right_hand = hand2;
    else
	figure->roles[h1].figures.moves[0].join_left_hand = hand2;
    if ( hand2&HAND_RIGHT_MASK )
	figure->roles[h2].figures.moves[0].join_right_hand = hand1;
    else
	figure->roles[h2].figures.moves[0].join_left_hand = hand1;
}

static void initialPositionsFigure(Figure *figure) {
    int i;

    switch ( figure->formation ) {
      case sp_squaredSet:
	assert(figure->people==8);
	moveTo(&figure->dancers[0],256+128,64,0);
	moveTo(&figure->dancers[1],512+128,64,0);
	moveTo(&figure->dancers[2],1024-64,256+128,90);
	moveTo(&figure->dancers[3],1024-64,512+128,90);
	moveTo(&figure->dancers[4],512+128,1024-64,180);
	moveTo(&figure->dancers[5],256+128,1024-64,180);
	moveTo(&figure->dancers[6],64,512+128,270);
	moveTo(&figure->dancers[7],64,256+128,270);
#if 0
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsDancers(figure,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,4|HAND_RIGHT_MASK,5|HAND_LEFT_MASK);
	joinHandsDancers(figure,6|HAND_RIGHT_MASK,7|HAND_LEFT_MASK);
#endif
      break;
      case sp_rect6Set:
	assert(figure->people==12);
	moveTo(&figure->dancers[0], 256+128,512+64,0);
	moveTo(&figure->dancers[1], 512+128,512+64,0);
	moveTo(&figure->dancers[2], 768+128,512+64,0);
	moveTo(&figure->dancers[3],1024+128,512+64,0);
	moveTo(&figure->dancers[4],1536-(64+128),512+256+128,90);
	moveTo(&figure->dancers[5],1536-(64+128),512+512+128,90);
	moveTo(&figure->dancers[6],1024+128,2048-512-64,180);
	moveTo(&figure->dancers[7], 768+128,2048-512-64,180);
	moveTo(&figure->dancers[8], 512+128,2048-512-64,180);
	moveTo(&figure->dancers[9], 256+128,2048-512-64,180);
	moveTo(&figure->dancers[10], 64,512+512+128,270);
	moveTo(&figure->dancers[11], 64,512+256+128,270);
#if 0
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsDancers(figure,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,4|HAND_RIGHT_MASK,5|HAND_LEFT_MASK);
	joinHandsDancers(figure,6|HAND_RIGHT_MASK,7|HAND_LEFT_MASK);
	joinHandsDancers(figure,8|HAND_RIGHT_MASK,9|HAND_LEFT_MASK);
	joinHandsDancers(figure,10|HAND_RIGHT_MASK,11|HAND_LEFT_MASK);
#endif
      break;
      case sp_facingCouples:
	assert(figure->people==4);
	moveTo(&figure->dancers[0],256+64,    64,0);
	moveTo(&figure->dancers[1],512+64,256+64,180);
	moveTo(&figure->dancers[2],512+64,256+64,180);
	moveTo(&figure->dancers[3],256+64,    64,0);
#if 0
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsDancers(figure,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
#endif
      break;
#if 0
      case sp_facingCouplesProper:
	assert(figure->people==4);
	moveTo(&figure->dancers[0],256+64,    64,0);
	moveTo(&figure->dancers[1],512+64,256+64,180);
	moveTo(&figure->dancers[2],512+64,    64,0);
	moveTo(&figure->dancers[3],256+64,256+64,180);
      break;
#endif
      case sp_facingPeople:
	assert(figure->people==2);
	moveTo(&figure->dancers[0],256+64,    64,0);
	moveTo(&figure->dancers[1],256+64,256+64,180);
      break;
      case sp_couple:
	assert(figure->people==2);
	moveTo(&figure->dancers[0],256+64,64,0);
	moveTo(&figure->dancers[1],512+64,64,0);
#if 0
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
#endif
      break;
      case sp_singleton:
	assert(figure->people==1);
	moveTo(&figure->dancers[0],256+64,64,0);
      break;
      case sp_rightHandWave:
	assert(figure->people==4);
	moveTo(&figure->dancers[0],432,384,-90);
	moveTo(&figure->dancers[1],432,128,-90);
	moveTo(&figure->dancers[2],464,0,90);
	moveTo(&figure->dancers[3],464,256,90);
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,3|HAND_RIGHT_MASK);
	joinHandsDancers(figure,1|HAND_LEFT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,2|HAND_RIGHT_MASK,1|HAND_RIGHT_MASK);
      break;
      case sp_leftHandWave:
	assert(figure->people==4);
	moveTo(&figure->dancers[0],432,384,90);
	moveTo(&figure->dancers[1],432,128,90);
	moveTo(&figure->dancers[2],464,0,-90);
	moveTo(&figure->dancers[3],464,256,-90);
	joinHandsDancers(figure,0|HAND_LEFT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,1|HAND_RIGHT_MASK,3|HAND_RIGHT_MASK);
	joinHandsDancers(figure,2|HAND_LEFT_MASK,1|HAND_LEFT_MASK);
      break;
      case sp_2rightHandWave:
	assert(figure->people==8);
	moveTo(&figure->dancers[0],432,384,-90);
	moveTo(&figure->dancers[1],432,128,-90);
	moveTo(&figure->dancers[2],464,0,90);
	moveTo(&figure->dancers[3],464,256,90);
	moveTo(&figure->dancers[4],512+432,384,-90);
	moveTo(&figure->dancers[5],512+432,128,-90);
	moveTo(&figure->dancers[6],512+464,0,90);
	moveTo(&figure->dancers[7],512+464,256,90);
	joinHandsDancers(figure,0|HAND_RIGHT_MASK,3|HAND_RIGHT_MASK);
	joinHandsDancers(figure,1|HAND_LEFT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,2|HAND_RIGHT_MASK,1|HAND_RIGHT_MASK);
	joinHandsDancers(figure,4|HAND_RIGHT_MASK,7|HAND_RIGHT_MASK);
	joinHandsDancers(figure,5|HAND_LEFT_MASK,7|HAND_LEFT_MASK);
	joinHandsDancers(figure,6|HAND_RIGHT_MASK,5|HAND_RIGHT_MASK);
      break;
      case sp_2leftHandWave:
	assert(figure->people==8);
	moveTo(&figure->dancers[0],432,384,90);
	moveTo(&figure->dancers[1],432,128,90);
	moveTo(&figure->dancers[2],464,0,-90);
	moveTo(&figure->dancers[3],464,256,-90);
	moveTo(&figure->dancers[0],512+432,384,90);
	moveTo(&figure->dancers[1],512+432,128,90);
	moveTo(&figure->dancers[2],512+464,0,-90);
	moveTo(&figure->dancers[3],512+464,256,-90);
	joinHandsDancers(figure,0|HAND_LEFT_MASK,3|HAND_LEFT_MASK);
	joinHandsDancers(figure,1|HAND_RIGHT_MASK,3|HAND_RIGHT_MASK);
	joinHandsDancers(figure,2|HAND_LEFT_MASK,1|HAND_LEFT_MASK);
	joinHandsDancers(figure,4|HAND_LEFT_MASK,7|HAND_LEFT_MASK);
	joinHandsDancers(figure,5|HAND_RIGHT_MASK,7|HAND_RIGHT_MASK);
	joinHandsDancers(figure,6|HAND_LEFT_MASK,5|HAND_LEFT_MASK);
      break;
      case sp_dupleMinor:
      case sp_becket:
      case sp_becketCCW:
      case sp_shortWaves:
      case sp_threeFaceThree:
      case sp_fourFaceFour:
      case sp_tempest:
      case sp_quadrupleMinorBecket:
      case sp_tripleMinor:
      case sp_scottishDupleMinor:
      case sp_scottishTripleMinor:
      default:
	assert(false);
      break;
      case sp_2Couple:
      case sp_3Couple:
      case sp_4Couple:
      case sp_5Couple:
      case sp_6Couple:
      case sp_7Couple:
      case sp_8Couple:
	/* assert(figure->people==6); */
	for ( i=0; i<figure->people/2; ++i ) {
	    if ( figure->improper_mask&(1<<i) ) {
		moveTo(&figure->dancers[i  ],64+256*i,320,180);
		moveTo(&figure->dancers[i+1],64+256*i, 64,0);
	    } else {
		moveTo(&figure->dancers[i  ],64+256*i, 64,180);
		moveTo(&figure->dancers[i+1],64+256*i,320,0);
	    }
	}
      break;
      case sp_3CplCircle:
	moveTo(&figure->dancers[0], 64,448,-90);
	moveTo(&figure->dancers[1], 64,192,-90);
	moveTo(&figure->dancers[2],286, 64, 30);
	moveTo(&figure->dancers[3],508,192, 30);
	moveTo(&figure->dancers[4],508,448,150);
	moveTo(&figure->dancers[5],286,576,150);
      break;
      case sp_5CplCircle:
	moveTo(&figure->dancers[0], 64,488,-90);
	moveTo(&figure->dancers[1], 64,288,-90);
	moveTo(&figure->dancers[2],182,126,342);
	moveTo(&figure->dancers[3],372, 64,342);
	moveTo(&figure->dancers[4],562,126, 54);
	moveTo(&figure->dancers[5],680,288, 54);
	moveTo(&figure->dancers[6],680,488,126);
	moveTo(&figure->dancers[7],562,650,126);
	moveTo(&figure->dancers[8],372,712,198);
	moveTo(&figure->dancers[9],182,650,198);
      break;
      case sp_6CplCircle:
	moveTo(&figure->dancers[0], 34,384,-90);
	moveTo(&figure->dancers[1], 34,640,-90);
	moveTo(&figure->dancers[2],384, 34,-30);
	moveTo(&figure->dancers[3],162,162,-30);
	moveTo(&figure->dancers[4],862,162, 30);
	moveTo(&figure->dancers[5],640, 34, 30);
	moveTo(&figure->dancers[6],990,640, 90);
	moveTo(&figure->dancers[7],990,384, 90);
	moveTo(&figure->dancers[8],640,990,150);
	moveTo(&figure->dancers[9],862,862,150);
	moveTo(&figure->dancers[10],162,862,210);
	moveTo(&figure->dancers[11],384,990,210);
      break;
      case sp_7CplCircle:
	moveTo(&figure->dancers[0],-40,384,-90);
	moveTo(&figure->dancers[1],-40,636,-90);
	moveTo(&figure->dancers[2],268,  1,-39);
	moveTo(&figure->dancers[3], 71,158,-39);
	moveTo(&figure->dancers[4],759,  3, 13);
	moveTo(&figure->dancers[5],514,-54, 13);
	moveTo(&figure->dancers[6],1064,388, 64);
	moveTo(&figure->dancers[7],956,161, 64);
	moveTo(&figure->dancers[8],953,866,116);
	moveTo(&figure->dancers[9],1063,640,116);
	moveTo(&figure->dancers[10],510,1078,167);
	moveTo(&figure->dancers[11],755,1023,167);
	moveTo(&figure->dancers[12], 68,864,219);
	moveTo(&figure->dancers[13],265,1021,219);
      break;
      case sp_square3:
	moveTo(&figure->dancers[0],256,  0,  0);
	moveTo(&figure->dancers[1],512,  0,  0);
	moveTo(&figure->dancers[2],768,  0,  0);

	moveTo(&figure->dancers[3],1024,256, 90);
	moveTo(&figure->dancers[4],1024,512, 90);
	moveTo(&figure->dancers[5],1024,768, 90);

	moveTo(&figure->dancers[6],768,1024,180);
	moveTo(&figure->dancers[7],512,1024,180);
	moveTo(&figure->dancers[8],256,1024,180);

	moveTo(&figure->dancers[9],  0,768,-90);
	moveTo(&figure->dancers[10],  0,512,-90);
	moveTo(&figure->dancers[11],  0,256,-90);
      break;
      case sp_custom:
      case sp_custom3:		/* Don't know what to do with this */
	for ( i=0; i<figure->people; ++i )
	    moveTo(&figure->dancers[i],128+(i%4)*256,64+(i/4)*128, 0 );
      break;
    }
}

static void initialPositionsDance(Dance *dance,long roleMask) {
    int i;

    switch ( dance->formation ) {
	/* For square dances I place the band below */
      case sp_squaredSet:
	assert(dance->role_cnt==8);
	moveTo(&dance->roles[0],256+128,64,0);
	moveTo(&dance->roles[1],512+128,64,0);
	moveTo(&dance->roles[2],1024-64,256+128,90);
	moveTo(&dance->roles[3],1024-64,512+128,90);
	moveTo(&dance->roles[4],512+128,1024-64,180);
	moveTo(&dance->roles[5],256+128,1024-64,180);
	moveTo(&dance->roles[6],64,512+128,270);
	moveTo(&dance->roles[7],64,256+128,270);
#if 0
	joinHandsRoles(dance,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsRoles(dance,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
	joinHandsRoles(dance,4|HAND_RIGHT_MASK,5|HAND_LEFT_MASK);
	joinHandsRoles(dance,6|HAND_RIGHT_MASK,7|HAND_LEFT_MASK);
#endif
      break;

      case sp_rect6Set:
	assert(dance->role_cnt==12);
	moveTo(&dance->roles[0], 256+128,512+64,0);
	moveTo(&dance->roles[1], 512+128,512+64,0);
	moveTo(&dance->roles[2], 768+128,512+64,0);
	moveTo(&dance->roles[3],1024+128,512+64,0);
	moveTo(&dance->roles[4],1536-(64+128),512+256+128,90);
	moveTo(&dance->roles[5],1536-(64+128),512+512+128,90);
	moveTo(&dance->roles[6],1024+128,2048-512-64,180);
	moveTo(&dance->roles[7], 768+128,2048-512-64,180);
	moveTo(&dance->roles[8], 512+128,2048-512-64,180);
	moveTo(&dance->roles[9], 256+128,2048-512-64,180);
	moveTo(&dance->roles[10], 64,512+512+128,270);
	moveTo(&dance->roles[11], 64,512+256+128,270);
#if 0
	joinHandsRoles(dance,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsRoles(dance,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
	joinHandsRoles(dance,4|HAND_RIGHT_MASK,5|HAND_LEFT_MASK);
	joinHandsRoles(dance,6|HAND_RIGHT_MASK,7|HAND_LEFT_MASK);
	joinHandsRoles(dance,8|HAND_RIGHT_MASK,9|HAND_LEFT_MASK);
	joinHandsRoles(dance,10|HAND_RIGHT_MASK,11|HAND_LEFT_MASK);
#endif
      break;
	/* For contra/english lines I place the band to the left */
      case sp_facingCouples:
	assert(dance->role_cnt==4);
	moveTo(&dance->roles[0],256+64,    64,0);
	moveTo(&dance->roles[1],512+64,256+64,180);
	moveTo(&dance->roles[2],512+64,256+64,180);
	moveTo(&dance->roles[3],256+64,    64,0);
#if 0
	joinHandsDancers(dance,0|HAND_RIGHT_MASK,1|HAND_LEFT_MASK);
	joinHandsDancers(dance,2|HAND_RIGHT_MASK,3|HAND_LEFT_MASK);
#endif
      break;
#if 0
      case sp_facingCouplesProper:
	assert(dance->role_cnt==4);
	moveTo(&dance->roles[0],256+64,    64,0);
	moveTo(&dance->roles[1],512+64,256+64,180);
	moveTo(&dance->roles[2],512+64,    64,0);
	moveTo(&dance->roles[3],256+64,256+64,180);
      break;
#endif
      case sp_facingPeople:
      case sp_couple:
      case sp_singleton:
      case sp_rightHandWave:
      case sp_leftHandWave:
      case sp_2rightHandWave:
      case sp_2leftHandWave:
      default:
	assert(false);
      break;
      case sp_scottishDupleMinor:
      case sp_dupleMinor:
	assert(dance->role_cnt==8);
	for ( i=0; i<2; ++i ) {
	    /* Scottish improper dances have the dancers cross over on the second gong (the first gong is for honouring) */
	    if ( (dance->improper_mask&(1<<i)) && dance->style!=sp_scottishDupleMinor ) {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*i,320,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*i, 64,0);
	    } else {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*i, 64,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*i,320,0);
	    }
	}
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	if ( dance->style==ds_contra ) {
	    danceFindRole(dance,r_1s,s_male)->figures.moves[0].degrees   = -90;
	    danceFindRole(dance,r_1s,s_female)->figures.moves[0].degrees = -90;
	    danceFindRole(dance,r_2s,s_male)->figures.moves[0].degrees   = 90;
	    danceFindRole(dance,r_2s,s_female)->figures.moves[0].degrees = 90;
	    danceFindRole(dance,r_outAtBottom,s_male)->figures.moves[0].degrees   = -90;
	    danceFindRole(dance,r_outAtBottom,s_female)->figures.moves[0].degrees = -90;
	    danceFindRole(dance,r_outAtTop,s_male)->figures.moves[0].degrees   = 90;
	    danceFindRole(dance,r_outAtTop,s_female)->figures.moves[0].degrees = 90;
	}
	i=8;
      break;
      case sp_becket:
	/* I'm only supporting Becket dances where the progression happens */
	/*  leaving a couple out, on the men's side of the line at the top */
	/* There are other styles: progression happens improper, or on the woman's side */
	/*   !!!!!! */
	moveTo(danceFindRole(dance,r_1s,s_male)  ,576,320,180);
	moveTo(danceFindRole(dance,r_1s,s_female),320,320,180);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,320,64,0);
	moveTo(danceFindRole(dance,r_2s,s_female),576,64,0);
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	i=8;
      break;
      case sp_becketCCW:
	moveTo(danceFindRole(dance,r_1s,s_male)  ,320,64,0);
	moveTo(danceFindRole(dance,r_1s,s_female),576,64,0);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,576,320,180);
	moveTo(danceFindRole(dance,r_2s,s_female),320,320,180);
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	i=8;
      break;
      case sp_shortWaves:
	moveTo(danceFindRole(dance,r_1s,s_male)  ,432,384,-90);
	moveTo(danceFindRole(dance,r_1s,s_female),432,128,-90);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,464,0,90);
	moveTo(danceFindRole(dance,r_2s,s_female),464,256,90);
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	joinHandsRoles(dance,0|HAND_RIGHT_MASK,3|HAND_RIGHT_MASK);
	joinHandsRoles(dance,1|HAND_LEFT_MASK,3|HAND_LEFT_MASK);
	joinHandsRoles(dance,2|HAND_RIGHT_MASK,1|HAND_RIGHT_MASK);
	i=8;
      break;
      case sp_dupleMinorProgressed:
	assert(dance->role_cnt==8);
	for ( i=0; i<2; ++i ) {
	    if ( dance->improper_mask&(1<<i) ) {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*(1-i),320,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*(1-i), 64,0);
	    } else {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*(1-i), 64,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*(1-i),320,0);
	    }
	}
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	if ( dance->style==ds_contra ) {
	    danceFindRole(dance,r_1s,s_male)->figures.moves[0].degrees   = 90;
	    danceFindRole(dance,r_1s,s_female)->figures.moves[0].degrees = 90;
	    danceFindRole(dance,r_2s,s_male)->figures.moves[0].degrees   = -90;
	    danceFindRole(dance,r_2s,s_female)->figures.moves[0].degrees = -90;
	    danceFindRole(dance,r_outAtBottom,s_male)->figures.moves[0].degrees   = 90;
	    danceFindRole(dance,r_outAtBottom,s_female)->figures.moves[0].degrees = 90;
	    danceFindRole(dance,r_outAtTop,s_male)->figures.moves[0].degrees   = -90;
	    danceFindRole(dance,r_outAtTop,s_female)->figures.moves[0].degrees = -90;
	}
	i=8;
      break;
      case sp_threeFaceThree:
	/* I'm ignoring improper here */
	moveTo(danceFindRole(dance,r_1s,s_left)  ,64,576,-90);
	moveTo(danceFindRole(dance,r_1s,s_center),64,320,-90);
	moveTo(danceFindRole(dance,r_1s,s_right) ,64,64 ,-90);
	moveTo(danceFindRole(dance,r_2s,s_left)   ,320,64,90);
	moveTo(danceFindRole(dance,r_2s,s_center),320,320,90);
	moveTo(danceFindRole(dance,r_2s,s_right) ,320,576,90);

	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
      break;
      case sp_fourFaceFour:
	/* I'm ignoring improper here */
	moveTo(danceFindRole(dance,r_1sleft ,s_male)  ,320,832,-90);
	moveTo(danceFindRole(dance,r_1sleft ,s_female),320,576,-90);
	moveTo(danceFindRole(dance,r_1sright,s_male)  ,320,320,-90);
	moveTo(danceFindRole(dance,r_1sright,s_female),320,64,-90);
	moveTo(danceFindRole(dance,r_2sleft ,s_male)  ,832,64,90);
	moveTo(danceFindRole(dance,r_2sleft ,s_female),832,320,90);
	moveTo(danceFindRole(dance,r_2sright,s_male)  ,832,576,90);
	moveTo(danceFindRole(dance,r_2sright,s_female),832,832,90);

	copyRolesMoveTo(dance,r_outAtBottomLeft,r_1sleft);
	copyRolesMoveTo(dance,r_outAtBottomRight,r_1sright);
	copyRolesMoveTo(dance,r_outAtTopLeft,r_2sleft);
	copyRolesMoveTo(dance,r_outAtTopRight,r_2sright);
      break;
      case sp_tempest:
	/* I'm ignoring improper here */
	moveTo(danceFindRole(dance,r_1sleft ,s_male)  ,320,832,-90);
	moveTo(danceFindRole(dance,r_1sleft ,s_female),320,576,-90);
	moveTo(danceFindRole(dance,r_1sright,s_male)  ,320,320,-90);
	moveTo(danceFindRole(dance,r_1sright,s_female),320,64,-90);
	moveTo(danceFindRole(dance,r_2sleft ,s_male)  ,448,-64,0);
	moveTo(danceFindRole(dance,r_2sleft ,s_female),704,-64,0);
	moveTo(danceFindRole(dance,r_2sright,s_male)  ,704,960,180);
	moveTo(danceFindRole(dance,r_2sright,s_female),448,960,180);

	copyRolesMoveTo(dance,r_outAtBottomLeft,r_1sleft);
	copyRolesMoveTo(dance,r_outAtBottomRight,r_1sright);
	copyRolesMoveTo(dance,r_outAtTopLeft,r_2sleft);
	copyRolesMoveTo(dance,r_outAtTopRight,r_2sright);
      break;
      case sp_quadrupleMinorBecket:
	/* I'm ignoring improper here */
	moveTo(danceFindRole(dance,r_1sleft ,s_male)  ,576,320,180);
	moveTo(danceFindRole(dance,r_1sleft ,s_female),320,320,180);
	moveTo(danceFindRole(dance,r_1sright,s_male)  ,320,64,0);
	moveTo(danceFindRole(dance,r_1sright,s_female),320,320,0);
	moveTo(danceFindRole(dance,r_2sleft ,s_male)  ,832,64,0);
	moveTo(danceFindRole(dance,r_2sleft ,s_female),1088,64,0);
	moveTo(danceFindRole(dance,r_2sright,s_male)  ,1088,320,180);
	moveTo(danceFindRole(dance,r_2sright,s_female),832,320,180);

	copyRolesMoveTo(dance,r_outAtBottomLeft,r_1sleft);
	copyRolesMoveTo(dance,r_outAtBottomRight,r_1sright);
	copyRolesMoveTo(dance,r_outAtTopLeft,r_2sleft);
	copyRolesMoveTo(dance,r_outAtTopRight,r_2sright);
      break;
      case sp_tripleMinor:
      case sp_scottishTripleMinor:
	for ( i=0; i<3; ++i ) {
	    /* In a scottish improper dance, dancers cross over at the second gong (first gong is for honouring) */
	    if ( (dance->improper_mask&(1<<i)) && dance->style!=sp_scottishTripleMinor ) {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*i,320,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*i, 64,0);
	    } else {
		moveTo(danceFindRole(dance,i,s_male)  ,320+256*i, 64,180);
		moveTo(danceFindRole(dance,i,s_female),320+256*i,320,0);
	    }
	}
	copyRolesMoveTo(dance,r_outAtTop,r_2s);
	copyRolesMoveTo(dance,r_outAtTop1of2,r_2s);
	copyRolesMoveTo(dance,r_outAtTop2of2,r_2s);
	copyRolesMoveTo(dance,r_outAtBottom,r_1s);
	copyRolesMoveTo(dance,r_outAtBottom1of2,r_1s);
	copyRolesMoveTo(dance,r_outAtBottom1of2,r_1s);
      break;
      case sp_2Couple:
      case sp_3Couple:
      case sp_4Couple:
      case sp_5Couple:
      case sp_6Couple:
      case sp_7Couple:
      case sp_8Couple:
      case sp_custom:
	for ( i=0; i<dance->role_cnt/2; ++i ) {
	    if ( dance->improper_mask&(1<<i) ) {
		moveTo(&dance->roles[2*i  ],64+256*i,320,180);
		moveTo(&dance->roles[2*i+1],64+256*i, 64,0);
	    } else {
		moveTo(&dance->roles[2*i  ],64+256*i, 64,180);
		moveTo(&dance->roles[2*i+1],64+256*i,320,0);
	    }
	}
      break;
      case sp_3CplCircle:
	moveTo(danceFindRole(dance,r_1s,s_male)  , 64,448,-90);
	moveTo(danceFindRole(dance,r_1s,s_female), 64,192,-90);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,286, 64, 30);
	moveTo(danceFindRole(dance,r_2s,s_female),508,192, 30);
	moveTo(danceFindRole(dance,r_3s,s_male)  ,508,448,150);
	moveTo(danceFindRole(dance,r_3s,s_female),286,576,150);
      break;
      case sp_5CplCircle:
	moveTo(danceFindRole(dance,r_1s,s_male)  , 64,488,-90);
	moveTo(danceFindRole(dance,r_1s,s_female), 64,288,-90);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,182,126,342);
	moveTo(danceFindRole(dance,r_2s,s_female),372, 64,342);
	moveTo(danceFindRole(dance,r_3s,s_male)  ,562,126, 54);
	moveTo(danceFindRole(dance,r_3s,s_female),680,288, 54);
	moveTo(danceFindRole(dance,r_4s,s_male)  ,680,488,126);
	moveTo(danceFindRole(dance,r_4s,s_female),562,650,126);
	moveTo(danceFindRole(dance,r_5s,s_male)  ,372,712,198);
	moveTo(danceFindRole(dance,r_5s,s_female),182,650,198);
      break;
      case sp_6CplCircle:
	moveTo(danceFindRole(dance,r_1s,s_male)  , 34,384,-90);
	moveTo(danceFindRole(dance,r_1s,s_female), 34,640,-90);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,384, 34,-30);
	moveTo(danceFindRole(dance,r_2s,s_female),162,162,-30);
	moveTo(danceFindRole(dance,r_3s,s_male)  ,862,162, 30);
	moveTo(danceFindRole(dance,r_3s,s_female),640, 34, 30);
	moveTo(danceFindRole(dance,r_4s,s_male)  ,990,640, 90);
	moveTo(danceFindRole(dance,r_4s,s_female),990,384, 90);
	moveTo(danceFindRole(dance,r_5s,s_male)  ,640,990,150);
	moveTo(danceFindRole(dance,r_5s,s_female),862,862,150);
	moveTo(danceFindRole(dance,r_6s,s_male)  ,162,862,210);
	moveTo(danceFindRole(dance,r_6s,s_female),384,990,210);
      break;
      case sp_7CplCircle:
	moveTo(danceFindRole(dance,r_1s,s_male)  ,-40,384,-90);
	moveTo(danceFindRole(dance,r_1s,s_female),-40,636,-90);
	moveTo(danceFindRole(dance,r_2s,s_male)  ,268,  1,-39);
	moveTo(danceFindRole(dance,r_2s,s_female), 71,158,-39);
	moveTo(danceFindRole(dance,r_3s,s_male)  ,759,  3, 13);
	moveTo(danceFindRole(dance,r_3s,s_female),514,-54, 13);
	moveTo(danceFindRole(dance,r_4s,s_male)  ,1064,388, 64);
	moveTo(danceFindRole(dance,r_4s,s_female),956,161, 64);
	moveTo(danceFindRole(dance,r_5s,s_male)  ,953,866,116);
	moveTo(danceFindRole(dance,r_5s,s_female),1063,640,116);
	moveTo(danceFindRole(dance,r_6s,s_male)  ,510,1078,167);
	moveTo(danceFindRole(dance,r_6s,s_female),755,1023,167);
	moveTo(danceFindRole(dance,r_7s,s_male)  , 68,864,219);
	moveTo(danceFindRole(dance,r_7s,s_female),265,1021,219);
      break;
      case sp_square3:
	moveTo(danceFindRole(dance,r_1s,s_left)  ,256,  0,  0);
	moveTo(danceFindRole(dance,r_1s,s_center),512,  0,  0);
	moveTo(danceFindRole(dance,r_1s,s_right) ,768,  0,  0);

	moveTo(danceFindRole(dance,r_2s,s_left)  ,1024,256, 90);
	moveTo(danceFindRole(dance,r_2s,s_center),1024,512, 90);
	moveTo(danceFindRole(dance,r_2s,s_right) ,1024,768, 90);

	moveTo(danceFindRole(dance,r_3s,s_left)  ,768,1024,180);
	moveTo(danceFindRole(dance,r_3s,s_center),512,1024,180);
	moveTo(danceFindRole(dance,r_3s,s_right) ,256,1024,180);

	moveTo(danceFindRole(dance,r_4s,s_left)  ,  0,768,-90);
	moveTo(danceFindRole(dance,r_4s,s_center),  0,512,-90);
	moveTo(danceFindRole(dance,r_4s,s_right) ,  0,256,-90);
      break;
      case sp_custom3:
	for ( i=0; i<dance->role_cnt/3; ++i ) {
	    moveTo(&dance->roles[3*i  ],256*i,  0,i%2?90:-90);
	    moveTo(&dance->roles[3*i+1],256*i,256,i%2?90:-90);
	    moveTo(&dance->roles[3*i+2],256*i,512,i%2?90:-90);
	}
      break;
      case sp_circularMonople:
	moveTo(danceFindRole(dance,r_1s,s_male)  ,320,64,0);
	moveTo(danceFindRole(dance,r_1s,s_female),576,64,0);
      break;
      case sp_trioCircularMonople:
	moveTo(danceFindRole(dance,r_1s,s_left)  ,320,576,-90);
	moveTo(danceFindRole(dance,r_1s,s_center),320,320,-90);
	moveTo(danceFindRole(dance,r_1s,s_right),320,64,-90);
      break;
    }
}
    
Figure *danceNewFigure(enum danceStyle style,enum subStyle substyle,const char *figurename,const char *callgroup,
			enum startingPosition starting,unsigned int improper_mask,
			int numPeople) {
    Figure *figure;
    int i;

    if ( sizeof(peopleCntFromStartingPosition)/sizeof(peopleCntFromStartingPosition[0])!=
	    sp_custom3+1 ) {
	fprintf( stderr, "The enum startingPosition is out of sync with the array peopleCntFromStartingPosition.\n" );
exit( 1 );
    }

    figure = calloc(1,sizeof(Figure));
    figure->is_figure = true;
    figure->units     = 1024;
    figure->name      = strdup(figurename);
    figure->callGroup = strdup(callgroup);
    figure->style     = style;
    if ( style==ds_square )
	figure->substyle = substyle;
    else
	figure->substyle = ss_unspecified;
    figure->formation = starting;
    figure->improper_mask = improper_mask;
    if ( numPeople<=0 ) {
	numPeople = peopleCntFromStartingPosition[starting];
    }
    figure->people  = numPeople;
    figure->dancers = calloc(numPeople,sizeof(Person));
    for ( i=0; i<numPeople; ++i ) {
	figure->dancers[i].sex = (i&1) ? s_female : s_male;
	figure->dancers[i].couple_number = i/2+1;
	figure->dancers[i].effective_role = i/2;
	figure->dancers[i].figures.move_cnt = 0;
	figure->dancers[i].figures.move_max = 10;
	figure->dancers[i].figures.moves = calloc(figure->dancers[i].figures.move_max,sizeof(FigureSegment));
    }
    initialPositionsFigure(figure);
    
return( figure );
}

long danceRoleMask(enum startingPosition starting, int numPeople) {
    long roleMask;

    switch ( starting ) {
      case sp_circularMonople: case sp_trioCircularMonople:
	roleMask = (1<<r_1s);
      break;
      /*case sp_facingCouplesProper:*/
      case sp_facingCouples:
      case sp_2Couple:
        roleMask = (1<<r_1s) | (1<<r_2s);
      break;
      case sp_3Couple:
      case sp_3CplCircle:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s);
      break;
      case sp_squaredSet:
      case sp_4Couple:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) | (1<<r_4s);
      break;
      case sp_5Couple:
      case sp_5CplCircle:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) | (1<<r_4s) |
		(1<<r_5s);
      break;
      case sp_6Couple:
      case sp_rect6Set:
      case sp_6CplCircle:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) | (1<<r_4s) |
			(1<<r_5s) | (1<<r_6s);
      break;
      case sp_7Couple:
      case sp_7CplCircle:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) | (1<<r_4s) |
			(1<<r_5s) | (1<<r_6s) | (1<<r_7s);
      break;
      case sp_8Couple:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) | (1<<r_4s) |
			(1<<r_5s) | (1<<r_6s) | (1<<r_7s) | (1<r_8s);
      break;
      case sp_dupleMinor:
      case sp_becket:
      case sp_becketCCW:
      case sp_shortWaves:
      case sp_dupleMinorProgressed:
      case sp_scottishDupleMinor:
      case sp_threeFaceThree:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1L<<r_outAtTop) | (1L<<r_outAtBottom);
      break;
      case sp_fourFaceFour:
      case sp_tempest:
      case sp_quadrupleMinorBecket:
	roleMask = (1L<<r_1sleft) | (1L<<r_1sright) | (1L<<r_2sleft) | (1L<<r_2sright) |
		    (1L<<r_outAtTopLeft) | (1L<<r_outAtTopRight) |
		    (1L<<r_outAtBottomLeft) | (1L<<r_outAtBottomRight);
      break;
      case sp_tripleMinor:
      case sp_scottishTripleMinor:
	roleMask = (1<<r_1s) | (1<<r_2s) | (1<<r_3s) |
		(1L<<r_outAtTop) | (1L<<r_outAtBottom) |
		(1L<<r_outAtTop1of2) | (1L<<r_outAtBottom1of2) |
		(1L<<r_outAtTop2of2) | (1L<<r_outAtBottom2of2);
/*	if ( starting==sp_tripleMinor ) */
/*	    role_min = role_max; */
/*	else */
/*	    role_min = (1<<r_1s) | (1<<r_2s) | (1<<r_3s); */
      break;
      case sp_custom:
	roleMask = ~(-1<<((numPeople+1)/2));
      break;
      case sp_custom3:
	roleMask = ~(-1<<((numPeople+1)/3));
      break;
      default:
	assert(false);
    }
return( roleMask );
}

void danceResetToNew(Dance *dance,int numPeople) {
    int i, rcnt;
    long roleMask;
    int starting;

    if (( dance->formation==sp_custom || dance->formation==sp_custom3 ) && numPeople==0 )
	numPeople = dance->role_cnt;
    if ( dance->dancers!=NULL ) {
	for ( i=0; i<dance->people; ++i )
	    peopleFreeContents(&dance->dancers[i]);
	free( dance->dancers );
	dance->dancers = NULL;
    }
    if ( dance->roles!=NULL ) {
	for ( i=0; i<dance->role_cnt; ++i )
	    peopleFreeContents(&dance->roles[i]);
	free( dance->roles );
	dance->roles = NULL;
	dance->role_cnt = 0;
    }
    figureFreeCalls(dance);

    roleMask = danceRoleMask(dance->formation, numPeople);
    rcnt = 0;
    for ( i=r_1s; i<=r_last_unused; ++i )
	if ( roleMask&(1<<i))
	    ++rcnt;
    dance->roleMask = roleMask;
    dance->role_cnt = 2*rcnt;		/* each role in the mask has a m+f aspect so there are twice as many individuals */
    starting = dance->formation;
    if ( starting==sp_threeFaceThree || starting==sp_square3 || starting==sp_custom3 )
	dance->role_cnt = 3*rcnt;
    dance->roles = calloc(dance->role_cnt,sizeof(Person));

    rcnt = 0;
    if ( starting==sp_threeFaceThree || starting==sp_square3 || starting==sp_custom3 ) {
	for ( i=r_1s; i<r_last_unused; ++i ) {
	    if ( roleMask&(1<<i)) {
		dance->roles[rcnt].sex = s_left;
		dance->roles[rcnt].couple_number = rcnt/3+1;
		dance->roles[rcnt].effective_role = i;
		dance->roles[rcnt].figures.move_max = 10;
		dance->roles[rcnt].figures.moves = calloc(dance->roles[rcnt].figures.move_max,sizeof(FigureSegment));
		++rcnt;
		dance->roles[rcnt].sex = s_center;
		dance->roles[rcnt].couple_number = rcnt/3+1;
		dance->roles[rcnt].effective_role = i;
		dance->roles[rcnt].figures.move_max = 10;
		dance->roles[rcnt].figures.moves = calloc(dance->roles[rcnt].figures.move_max,sizeof(FigureSegment));
		++rcnt;
		dance->roles[rcnt].sex = s_right;
		dance->roles[rcnt].couple_number = rcnt/3+1;
		dance->roles[rcnt].effective_role = i;
		dance->roles[rcnt].figures.move_max = 10;
		dance->roles[rcnt].figures.moves = calloc(dance->roles[rcnt].figures.move_max,sizeof(FigureSegment));
		++rcnt;
	    }
	}
    } else {
	for ( i=r_1s; i<r_last_unused; ++i ) {
	    if ( roleMask&(1<<i)) {
		dance->roles[rcnt].sex = s_male;
		dance->roles[rcnt].couple_number = rcnt/2+1;
		dance->roles[rcnt].effective_role = i;
		dance->roles[rcnt].figures.move_max = 10;
		dance->roles[rcnt].figures.moves = calloc(dance->roles[rcnt].figures.move_max,sizeof(FigureSegment));
		++rcnt;
		dance->roles[rcnt].sex = s_female;
		dance->roles[rcnt].couple_number = rcnt/2+1;
		dance->roles[rcnt].effective_role = i;
		dance->roles[rcnt].figures.move_max = 10;
		dance->roles[rcnt].figures.moves = calloc(dance->roles[rcnt].figures.move_max,sizeof(FigureSegment));
		++rcnt;
	    }
	}
    }
    initialPositionsDance(dance,roleMask);
}

Dance *danceNewDance(enum danceStyle style,enum subStyle substyle,const char *dancename,
			const char *author,const char *music,int year,
			const char *interpreter,int year_interpreted,
			enum startingPosition starting,unsigned int improper_mask,
			int progression, int numPeople) {
    Dance *dance;

    if ( sizeof(peopleCntFromStartingPosition)/sizeof(peopleCntFromStartingPosition[0])!=
	    sp_custom3+1 ) {
	fprintf( stderr, "The enum startingPosition is out of sync with the array peopleCntFromStartingPosition.\n" );
exit( 1 );
    }

    dance = calloc(1,sizeof(Dance));
    dance->is_figure = false;
    dance->units     = 1024;
    dance->name      = strdup(dancename);
    if ( *author )
	dance->author= strdup(author);
    if ( *music )
	dance->music_name = strdup(music);
    if ( *interpreter )
	dance->interpreter= strdup(interpreter);
    dance->year_written     = year;
    dance->year_interpreted = year_interpreted;
    dance->style     = style;
    if ( style==ds_square )
	dance->substyle = substyle;
    else
	dance->substyle = ss_unspecified;
    dance->progression = progression;
    dance->formation = starting;
    dance->improper_mask = improper_mask;

    danceResetToNew(dance,numPeople);

return( dance );
}
