#include "pre_mus.h"
#include <ctype.h>

struct notes   *notep;

char    prevnote = 0,
        prevoctv = 0;

#ifdef junk
mon (s, c) char *s,
                c;
{
    fprintf (stderr, "%s bar %d beat %d c=%c\n", s, bar, beat, c);
}
#endif

getscore () {
    notep = notev + beat;
    while (getbar ());
}

getbar () {
    nextvischar ();
    visbackup ();
    if (!within_ms) {
	return 0;
    }
    if (part == 0)
	clearbar (bar, 1);
    getescape ();		/* e.g. \bps = 4. */
    if (!getrepeatbars ()) {
	getbartext ();
	while (getescape (), getnote ());
	if (!getbarline ()) {
	    if (!within_ms) {
		return 0;
	    }
	    visbackup ();
	    ioerror ("Invalid symbol \"%c\"", nextvischar (), 0);
	    nextvischar ();
	}
/* insert extra start bar if bar 0 full */
	if (part == 0 && bar == 1 && barv[0].b_length == piecev.p_bar_length) {
	    copybar (1, 0, 1);
	    clearbar (0, 1);
	    bar++;
	}
    }
    if (verbose == 2) {
	fprintf (stderr, "Leave getbar %d beat %d\n", bar, beat);
	barprint (bar - 1);
    }
    return 1;
}

getrepeatbars () {
    char    ch1 = nextvischar ();
    int     prevbar,
            prevbar1,
            prevbar2;
    int     pt;

    if (ch1 != ESCAPE) {
	visbackup ();
	return 0;
    }
    ch1 = nextvischar ();
    visbackup ();
/* look for repeated bars, either "\0,9", "\-2", "\'A'" */
    if (
	    (ch1 < '0' || ch1 > '9')
	    && ch1 != OTEXTSYM
	    && ch1 != UTEXTSYM
	    && ch1 != NTEXTSYM
	    && ch1 != '-'
	) {
	backup ();		/* past escape char as well */
	return (0);
    }

    if (verbose == 2)
	fprintf (stderr, "getrpt %d beat %d\n", bar, beat);
    prevbar1 = getbarno ();
    ch1 = nextvischar ();
    if (ch1 == ',') {		/* range of bar numbers */
	prevbar2 = getbarno ();
    }
    else {			/* only one bar */
	prevbar2 = prevbar1;
	visbackup ();
    }
    pt = part;
    if ((ch1 = nextvischar ()) == 'p') {/* difft part */
	pt = readint () - 1;
    }
    else
	visbackup ();

/* insert extra start bar if copying to bar 1? */
    if (reset == 0 && barv[prevbar1].b_length == piecev.p_bar_length) {
	fprintf (stderr, "Copied bar %d moved to bar %d\n", bar, bar + 1);
	copybar (bar + 1, bar, 1);
	clearbar (bar, 1);
	bar++;
	reset++;
    }

/* copy bars across */
    for (prevbar = prevbar1; prevbar <= prevbar2; prevbar++) {
	bar_first_note[bar][part] = bar_first_note[prevbar][pt];
	bar_last_note[bar][part] = bar_last_note[prevbar][pt];
	if (1 || part == 0) {
	    copybar (bar, prevbar, 0);
	}
	bar++;
	reset++;
    }

/* skip input to next barline */
    bar--;
    reset--;
    if (!getbarline ()) {
	fprintf (stderr, "Can't find barline after repeated bars\n");
	return 0;
    }
    bar_first_note[bar][part] = beat;
    if (verbose == 2)
	fprintf (stderr, "leave getrpt bar %d beat %d part %d first set to %d\n",
		bar, beat, part, bar_first_note[bar][part]);
    return 1;			/* repeat of earlier bars */
}

getescape () {
    char    ch = nextvischar ();
    if (ch == ESCAPE) {
	ch = nextvischar ();
	visbackup ();
/* first avoid picking out repeated bars, either "\0,9", "\-2", "\'A'" etc */
	if ((ch >= '0' && ch <= '9')
		|| ch == OTEXTSYM || ch == UTEXTSYM || ch == NTEXTSYM
		|| ch == '-') {
	    visbackup ();
	    return 0;
	}
	if (verbose == 3)
	    fprintf (stderr, "getparams bar %d beat %d\n", bar, beat);
	getparams (0);
	return 1;
    }
    else {
	visbackup ();
	return 0;
    }
}

getbartext () {
    gettext (&barv[bar].b_tover[partv[part].pt_end_stave]);
}

getnote () {
    notep = notev + beat;
    if (getval ()) {
	getnotetext ();
	getbeamend ();

	if (notep -> n_tnote == 0 || *(notep -> n_tnote) != NTEXTSYM
		|| '2' > *(notep -> n_tnote + 1)
		|| *(notep -> n_tnote + 1) > '7')
	    hdsq += notep -> n_length;
	if (bar_first_note[bar][part] == 0) {
	    bar_first_note[bar][part] = beat;
	}
	bar_last_note[bar][part] = beat + 1;
	beat++;
	notep++;
	return 1;
    }
    return 0;
}

getval () {
    char    ch1 = nextvischar (), ch2;
    int     pitch,
            octv,
            length,
            n_dots;
    backup ();
    if ((ch1 < 'a' || ch1 > 'g') && ch1 != RESTSYM &&
	    ch1 != BEAMSTART && ch1 != TIESTART && ch1 != GROUPSTART) {
	return 0;
    }
    getbeamstart ();
    ch1 = nextvischar ();

 /* should be a note of some sort */

 /*  letter or rest; if letter, check sharp or flat or natural */
    if (ch1 >= 'a' && ch1 <= 'g' || ch1 >= 'A' && ch1 <= 'G') {
	if (ch1 >= 'A' && ch1 <= 'G')
	    ch1 += 'a' - 'A';
	ch2 = nextvischar ();
    /* given natural or sharp or flat */
	if (ch2 == SAMESYM || ch2 == SHARPSYM || ch2 == FLATSYM) {
	    pitch = note_to_int (ch1, ch2);
	    ch2 = nextvischar ();
	/* no sharp or flat given */
	}
	else {
	    pitch = note_to_int (ch1, ' ');
	}

/* sort out the octv */
	octv = octv_now;
/* PREVOCTAVE, near to previous note */
	if (octv_mode == PREVOCTAVE && beat > 1) {
	    octv = prevoctv;
	    if ((prevnote == 'f' && ch1 >= 'c' && ch1 <= 'e')
		    || (prevnote == 'g' && ch1 >= 'd' && ch1 <= 'e')
		    || (prevnote == 'a' && ch1 == 'e')
		)
		octv--;
	    if ((prevnote == 'e' && (ch1 == 'f' || ch1 == 'g' || ch1 == 'a'))
		    || (prevnote == 'd' && ch1 >= 'f' && ch1 <= 'g')
		    || (prevnote == 'c' && ch1 == 'f')
		)
		octv++;
	}
	if (ch1 >= 'a' && ch1 <= 'g') {
	    prevnote = ch1;
	    prevoctv = octv;
	}
/* KEYOCTAVE : if default octv is w.r.t key */
	if (octv_mode == KEYOCTAVE) {
	    ;			/* no action for KEYOCTAVE */
	}
/* STAVEOCTAVE : default octv is w.r.t bottom space on stave = e */
	else
	    if (octv_mode == STAVEOCTAVE || octv_mode == PREVOCTAVE) {
		if (key_now > 'f' && ch1 >= 'f' && ch1 < key_now) {
		    octv--;
		}
		else
		    if
			(key_now < 'f' && (ch1 >= 'f' || ch1 < key_now)) {
			octv--;
		    }
	    }
/* COCTAVE : default octv is from middle C */
	    else {
		if (key_now > 'c' && ch1 >= 'c' && ch1 < key_now) {
		    octv--;
		}
		else
		    if (key_now < 'c' && (ch1 >= 'c' || ch1 < key_now)) {
			octv--;
		    }
	    }

	pitch += 'a' - root_now + 8;

    /*  get octv symbols	 */
	ch1 = ch2;
	while (ch1 == HIGHER || ch1 == LOWER) {
	    if (ch1 == HIGHER) {
		prevoctv++;
		octv++;
	    }
	    else {
		prevoctv--;
		octv--;
	    }
	    ch1 = nextvischar ();
	}

    /* or its a rest */
    }
    else
	if (ch1 == RESTSYM || ch1 == IRESTSYM) {
	    pitch = ch1;
	    octv = '0';
	    ch1 = nextvischar ();
	}
	else {
	    ioerror ("What's \"%c\" doing here?", ch1, 0);
	    return 0;
	}

 /* get length symbols */
    length = piecev.p_beat_length;
    n_dots = 0;
    while (ch1 == LONGER || ch1 == SHORTER || ch1 == '.') {
	if (ch1 == LONGER)
	    length *= 2;
	else
	    if (ch1 == SHORTER)
		length /= 2;
	    else		/* ch1 == '.' */
		n_dots++;
	ch1 = nextvischar ();
    }
    if (n_dots == 1)
	length += (length / 2);
    else
	if (n_dots == 2)
	    length += (length * 3 / 4);
	else
	    if (n_dots == 3)
		length += (length * 7 / 8);

    notep -> n_pitch = pitch;
    notep -> n_octv = octv;
    notep -> n_length = length;
    barv[bar].b_length += length;
    notep -> n_part = part;
    notep -> stickup = pt_updown;
    backup ();
    return 1;
}

getbeamstart () {
    char    ch1 = nextvischar ();
    notev[beat].n_beam = 0;
    notev[beat].n_tie_start = 0;
    notev[beat].n_group = 0;
    while (ch1 == BEAMSTART || ch1 == TIESTART || ch1 == GROUPSTART) {
	if (ch1 == BEAMSTART) {
	    notev[beat].n_beam = 1;/* start of beam */
	    if (in_beam)
		ioerror ("beamstart within beam", 0, 0);
	    in_beam = 1;
	}
	else
	    if (ch1 == TIESTART) {
		notev[beat].n_tie_start += 1;/* start of tie */
	    }
	    else
		if (ch1 == GROUPSTART) {
		    notev[beat].n_group = 1;/* start of n_group */
		}
	ch1 = nextvischar ();
    }
    backup ();
}

getbeamend () {
    char    ch1 = nextvischar ();
    while (ch1 == BEAMEND || ch1 == TIEEND || ch1 == GROUPEND) {
	if (ch1 == BEAMEND) {
	    notev[beat].n_beam = -1;
	    if (!in_beam)
		ioerror ("beamend without start", 0, 0);
	    in_beam = 0;
	}
	else
	    if (ch1 == GROUPEND)
		notev[beat].n_group = 0;
	    else {
		notev[beat].n_tie_end += 1;
	    }
	ch1 = nextvischar ();
    }
    backup ();
}

getnotetext () {
    gettext (&notep -> n_tnote);
}

getbarline () {
    char    ch1 = nextvischar (), ch2;
    int     end_type = 0;
    if (ch1 != BARSYM && ch1 != NBARSYM && ch1 != ':') {
	backup ();
	return 0;
    }
    if (barv[bar].b_new_stave = (ch1 == NBARSYM)) {
	ch1 = BARSYM;
    }
    ch2 = ch1;
    end_type = 0;
    ch1 = nextvischar ();
    if (ch1 == NBARSYM) {
	barv[bar].b_new_stave = 1;
	ch1 = BARSYM;
    }
    if (ch2 == ':') {
	if (ch1 == BARSYM) {	/* :| etc */
	    ch1 = nextvischar ();
	    if (ch1 == ':') {
		end_type = 'Q';	/* :|: */
	    }
	    else {
		end_type = 'R';	/* :| */
		backup ();
	    }
	}
	else {			/* : not followed by | */
	    backup ();
	    backup ();
	    return 0;
	}
    }
    else
	if (ch2 == BARSYM) {
	    if (ch1 >= 'A' && ch1 <= 'Z') {/* bar type |<letter> */
		nextvischar ();
		backup ();
		end_type = ch1;
	    }
	    else
		if (ch1 == ':') {
		    end_type = 'P';/* |: */
		}
		else
		    if (ch1 == BARSYM) {
			end_type = 'D';/* || */
		    }
		    else
			backup ();
	}

    if (barv[bar].b_end_type == 0)
	barv[bar].b_end_type = end_type;

    if (in_beam) {
	ioerror ("Unclosed beam", 0, 0);
	in_beam = 0;
    }

 /* if bar 0 is full, assume not lead-in, move bar 0 to bar 1 */
    if (bar == 0 && part == 0 && hdsq == piecev.p_bar_length) {
	copybar (bar + 1, bar, 1);
	clearbar (bar, 1);
	bar++;
	reset++;
    }				/* end copying bar 0 to 1 */

    checklength ();
    beamit (bar, bar_first_note[bar][part], bar_last_note[bar][part]);
    bar++;
    reset++;
    clearaccid ();
    if (bar >= NBARS) {
	ioerror ("Too many bars, max is %d", NBARS, 0);
    }
    bar_first_note[bar][part] = beat;
    return 1;
}

gettext (p) char  **p;
{
    int     nquote;
    char    term = 0,
            uc,
            pitch,
            firstchar,
            ch2;
    char    ch1 = nextvischar ();
    int     accids = accid_mode;
    accid_mode = EXPLACCID;
    *p = 0;
    while (ch1 == UTEXTSYM || ch1 == OTEXTSYM || ch1 == NTEXTSYM) {
	nquote = 0;
	if (*p == 0) {
	    *p = textp;
	}
	switch (ch1) {
	    case UTEXTSYM: 
		*textp++ = UTEXTSYM;
		nquote++;
		break;
	    case OTEXTSYM: 
		*textp++ = OTEXTSYM;
		break;
	    case NTEXTSYM: 
		*textp++ = NTEXTSYM;
		break;
	}
	if (term == ch1) {
	    textp--;
	    *(textp - 1) = '\n';
	}
	term = ch1;
	firstchar = 1;
	while ((*textp = nextchar ()) != term) {
	    if (*textp == UTEXTSYM)
		nquote++;
	    else
		if (nquote && chordtransp && firstchar) {
		    ch1 = *textp;
		    if (isalpha (ch1)) {
			ch2 = nextvischar ();
			if (ch1 >= 'A' && ch1 <= 'Z') {
			    uc = 'A' - 'a';
			    ch1 -= uc;
			}
			else
			    uc = 0;
			if (ch2 == '+' || ch2 == '-') {
			    pitch = note_to_int (ch1, ch2);
			}
			else {
			    pitch = note_to_int (ch1, ' ');
			    backup ();
			}
			*textp = 'a' + uc + pitch - root_now + 8;
			if (uc)
			    firstchar = 0;
		    }		/* whether ch1 is alpha */
		}		/* if not special symbol */
	    if (*textp == '\n')
		ioerror ("newline in text", 0, 0);
	    else
		if (*textp == '\/')
		    firstchar = 1;
		else
		    if (*textp == ESCAPE) {
			ch2 = nextchar ();
			switch (ch2) {
			    case 'n': 
				*textp = '\n';
				firstchar = 1;
				break;
			    default: 
				*++textp = ch2;
			}
		    }
	    textp++;
	}			/* end while ch1 != term */
	*textp++ = term;
	firstchar = 1;
	ch1 = nextvischar ();
    }
    *textp++ = 0;
    accid_mode = accids;
    backup ();
}

copybar (to, from, all) {
    int     i;
    struct bars *top = barv + to,
               *fromp = barv + from;
    if (verbose == 2) {
	fprintf (stderr, "Copy bar %d from bar %d %s\n",
		to, from, all ? "all" : "partial");
	barprint (to);
    }
    if (all)
	for (i = 0; i < NPARTS; i++) {
	    bar_first_note[to][i] = bar_first_note[from][i];
	    bar_last_note[to][i] = bar_last_note[from][i];
	}
    if (all) {
	for (i = 0; i < NSTAFFS; i++) {
	    top -> b_clef[i] = fromp -> b_clef[i];
	    top -> b_tover[i] = fromp -> b_tover[i];
	}
	top -> b_key = fromp -> b_key;
	top -> b_root = fromp -> b_root;
	top -> b_n_tsig = fromp -> b_n_tsig;
	top -> b_d_tsig = fromp -> b_d_tsig;
	top -> b_bps = fromp -> b_bps;
	top -> b_s_width = fromp -> b_s_width;
    }
    else {
	for (i = 0; i < NSTAFFS; i++) {
	    top -> b_clef[i] = 0;
	    top -> b_tover[i] = 0;
	}
/*	  top->b_key   = 0;
	top->b_root  = 0;
	top->b_n_tsig = 0;
	top->b_d_tsig = 0;
	top->b_bps   = 0; */
    }
    top -> b_length = fromp -> b_length;
    top -> b_nnotes = fromp -> b_nnotes;
    top -> b_new_stave = fromp -> b_new_stave;
    top -> b_end_type = fromp -> b_end_type;
}

clearbar (from, all) {
    int     i;
    struct bars *fromp = barv + from;
    if (all) {
	for (i = 0; i < NPARTS; i++) {
	    bar_first_note[from][i] = 0;
	    bar_last_note[from][i] = 0;
	}
	for (i = 0; i < NSTAFFS; i++) {
	    fromp -> b_clef[i] = 0;
	    fromp -> b_tover[i] = 0;
	}
	fromp -> b_bps = 0;
    }
    fromp -> b_end_type = 0;
    fromp -> b_key = 0;
    fromp -> b_root = 0;
    fromp -> b_n_tsig = 0;
    fromp -> b_d_tsig = 0;
    fromp -> b_s_width = 0;
    fromp -> b_length = 0;
    fromp -> b_nnotes = 0;
    fromp -> b_new_stave = 0;
}

