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

int     b_lengthpp[NPARTS],
        inn_group = 0;

get_note_or_bar (beat) {	/* get note in internal form */
    struct notes   *notep = notev + beat;
    struct bars *barp = barv + bar;
    char   *ch = &notep -> n_pitch,
            term = 0;
 /*    char **text = 0; /* to point to textover or under etc */
    char    c,
            firstchar,
            uc,
            under;
    int     n;

    *ch = nextvischar ();

 /* if run off end of .MS - .ME section, pretend barline */
    if (!within_ms) {
	if (barp -> b_end_type == 0)
	    barp -> b_end_type = BLTHICKL;
    /* set textover to null too */
	return BARSYM;
    }

 /* bar end details */
    if (*ch == BARSYM || *ch == NBARSYM) {
	barp -> b_new_stave = *ch == NBARSYM;
	barp -> b_stt_type = 0;
	*ch = nextvischar ();
	if (*ch <= 'Z' && *ch >= 'A') {
	    barp -> b_end_type = bartype (*ch);
	}
	else {
	    barp -> b_end_type = BLPLAIN;
	    backup ();
	}
    /* look for bar text here */
	while ((term = nextvischar ()) == UTEXTSYM
		|| term == OTEXTSYM || term == NTEXTSYM) {
	    switch (term) {
		case OTEXTSYM: 
		    if (barp -> b_tover[staff_now])
			ioerror ("textover re-defined", 0, 0);
		    barp -> b_tover[staff_now] = textp;
		    break;
		case UTEXTSYM: 
		    if (barp -> b_tunder[staff_now])
			ioerror ("textunder re-defined", 0, 0);
		    barp -> b_tunder[staff_now] = textp;
		    break;
		default: 
		    ioerror (
			    "Invalid char \"%c\" in bartext", term, 0);
	    }
	    while ((c = nextchar ()) != term) {
		*textp++ = c;
	    }
	    *textp++ = 0;
	}
	backup ();
	return BARSYM;
    }

 /* on-the-fly change */
    if (*ch == ESCAPE) {
	*ch = nextvischar ();
	switch (*ch) {
	    case 'c': 		/* clef */
		getclef ();
		break;
	    case 'k': 		/* output key */
		n = key_now;
		getkey ();
		barv[bar].b_key = key_now;
		break;
	    case 't': 		/* time sig */
		n = piecev.p_tsig_n;
		gettimesig ();
		barv[bar].b_n_tsig = tsig_n_now;
		barv[bar].b_d_tsig = tsig_d_now;
		break;
	    case 'p': 		/* another part */
		part = readint ();
		staff_now = partv[part].pt_end_stave;
		offset_now = staffv[0][staff_now].s_key_offset;
		clef_now = clefs_now[staff_now]
		    = staffv[0][staff_now].s_clef;
		barv[bar].b_length = 0;
		break;
	    case 'n': 		/* number of bars per stave */
		bps_now = barv[bar].b_bps = readint ();
		break;
	    case 'w': 		/* b_s_width */
		barv[bar].b_s_width =
		    (int) ((1.0 * readint () * reduction) / 100);
		break;
	    case 'r': 		/* b_restart */
		break;
	    default: 		/* unknown */
		ioerror ("Fly change not recognised \"%c\"\n", *ch, 0);
	}
	return ' ';
    }

 /* must be note of sorts */

    notep -> n_beam = 0;
    notep -> n_tie_start = 0;
    notep -> n_tie_end = 0;
    notep -> n_group = inn_group;
    notep -> n_tie_height = 0;
    notep -> n_x_stick = 0;
    notep -> n_head_x = 0;
    notep -> n_y_end_stick = 0;
    notep -> n_tover = 0;
    notep -> n_yover = HALFSTAVE;
    notep -> n_tunder = 0;
    notep -> n_yunder = -HALFSTAVE;
    notep -> n_tnote = 0;
    notep -> n_part = part;
    notep -> n_staff = partv[part].pt_end_stave;
    notep -> stickup = partv[part].pt_updown;
    notep -> n_mus_wrt_bar = barv[bar].b_length;
    if (inn_group)
	inn_group++;

    while (*ch == BEAMSTART || *ch == TIESTART || *ch == GROUPSTART) {
	if (*ch == BEAMSTART)
	    notep -> n_beam = 1;
	else
	    if (*ch == GROUPSTART) {
		notep -> n_group = inn_group = 1;
	    }
	    else
		if (*ch == TIESTART)
		    notep -> n_tie_start += 1;
	*ch = nextvischar ();
    }

    while ((*ch < PITCHDATUM - 7 || *ch > PITCHDATUM + 14)
	    && *ch != RESTSYM
	    && *ch != IRESTSYM) {
	ioerror ("What pitch?, note %d char \"%c\"", beat, *ch);
	*ch = nextvischar ();
    }

    notep -> n_octv = nextvischar ();

    notep -> n_length = readint ();
    term = nextvischar ();
    if (term == 'u') {
	notep -> stickup = 1;
	term = nextvischar ();
    }
    if (term == 'd') {
	notep -> stickup = -1;
	term = nextvischar ();
    }

 /* look for text */
    firstchar = 0;
    under = 0;
    while (term == UTEXTSYM || term == OTEXTSYM || term == NTEXTSYM) {
	switch (term) {
	    case OTEXTSYM: 
		notep -> n_tover = textp;
		break;
	    case UTEXTSYM: 
		firstchar = 1;
		notep -> n_tunder = textp;
		break;
	    case NTEXTSYM: 
		notep -> n_tnote = textp;
		break;
	    default: 
		notep -> n_tunder = textp;
		fprintf (stderr, "textunder");
		*textp++ = term;
	}
	under = term == UTEXTSYM;
	while ((c = nextchar ()) != term) {
	    if (under && chordtransp && firstchar && isalpha (c)) {
		if ('A' <= c && c <= 'Z') {
		    uc = 'A' - 'a';
		    c -= uc;
		}
		else
		    uc = 0;
		n = c - 'a' + key_now - 8 + offset_now;
		if (n < 0 || n >= 21)
		    fprintf (stderr, "Invalid n %d\n", n);
		c = scale[n][0] + uc;
		if (scale[n][1] != ' ') {
		    *textp++ = c;
		    if (scale[n][1] == '-') {/* "\u\(ft\d" for flat */
			append_text ("\\-");
		    }
		    else {	/* "\u\(sh\d" for sharp */
			append_text ("\\+");
		    }
		    c = *--textp;
		}
		if (uc)
		    firstchar = 0;
	    }
	    *textp++ = c;
	    if (c == '\n' || c == '\/')
		firstchar = 1;
	}
	*textp++ = 0;
	term = nextvischar ();
    }

    if (notep -> n_tnote == 0 || *notep -> n_tnote != '3')
	barv[bar].b_length = b_lengthpp[notep -> n_part] += notep -> n_length;

 /* look for end of beam */
    while (term == BEAMEND || term == TIEEND || term == GROUPEND) {
	if (term == BEAMEND)
	    notep -> n_beam = -1;
	else
	    if (term == GROUPEND)
		inn_group = 0;
	    else
		if (term == TIEEND)
		    notep -> n_tie_end += 1;
	term = nextvischar ();
    }

    print_ties (notep - notev);

 /* print summary for comment */
    if (get_monitor > 3)
	noteprint (beat);
    return term;
}

append_text (s) char   *s;
{
    while (*s)
	*textp++ = *s++;
}

getpiece () {			/* read a whole piece */
    struct bars *barp = barv;
    int     p;
    char    ch;
    textp = textv;		/* initialise text for comments */
    prev_key = 0;
    clearaccid ();
    part = 0;
    for (bar = 0; bar < NBARS; bar++)
	clearbar (bar, 0);
    bar = 0;
    stave = 0;
    staff = 0;
    staff_now = 0;
    beat = 0;
    bps_now = 8;
    offset_now = 0;
    clearbar (bar, beat);
    getparams ();
    if (get_monitor)
	fprintf (stderr, "Title: %s\n", piecev.left_title);
    for (p = 0; p < n_parts; p++)
	b_lengthpp[p] = 0;
    part = 0;
    while (within_ms) {
	if (ch = get_note_or_bar (beat),
		ch == BARSYM || ch == NBARSYM/* end of bar */
		|| !within_ms) {/* or end of piece */
	    if (!within_ms) {	/* end of piece */
		if (barp -> b_end_type == 0)
		    barp -> b_end_type = BLTHICKL;
	    }
	    barp -> b_last_note = beat;
	    barp -> b_nnotes = barp -> b_last_note - barp -> b_first_note;
	    barp -> b_length = b_lengthpp[0];
	    for (p = 1; p < n_parts; p++) {
		if (b_lengthpp[0] && b_lengthpp[p] &&
			b_lengthpp[0] != b_lengthpp[p])
		    ioerror ("Difft parts difft lengths bar %d", bar, 0);
		if (barp -> b_length < b_lengthpp[p])
		    barp -> b_length = b_lengthpp[p];
	    }
	    if (get_monitor > 2)
		barprint (bar);
	    bar++;
	    barp++;
	    for (p = 0; p < n_parts; p++)
		b_lengthpp[p] = 0;
	    clearbar (bar, beat);
	}
	else
	    if (ch == ' ') {	/* fly change */
		;
	    }			/* else ordinary note */
	    else
		beat++;
    }				/* end while still in .MS code */
    piecev.p_bars = bar - 1;
    piecev.p_nnotes = beat - 1;
    piecev.p_lead_notes = barv[0].b_last_note - barv[0].b_first_note;
}

getparams () {
    char    c;
    int     i;
 /* left_title */
    piecev.left_title = textp;
    while ((c = nextvischar ()) > 0 && c != UTEXTSYM);
    while ((c = nextchar ()) > 0 && c != UTEXTSYM)
	*textp++ = c;
    *textp++ = 0;
 /* centre left_title */
    piecev.centre_title = textp;
    while ((c = nextvischar ()) > 0 && c != UTEXTSYM);
    while ((c = nextchar ()) > 0 && c != UTEXTSYM)
	*textp++ = c;
    *textp++ = 0;
    piecev.right_title = textp;
    while ((c = nextvischar ()) > 0 && c != UTEXTSYM);
    while ((c = nextchar ()) > 0 && c != UTEXTSYM)
	*textp++ = c;
    *textp++ = 0;
 /* per stave */
    n_staffs = readint ();
    for (i = 0; i < n_staffs; i++) {
	clefs_now[i] =
	    staffv[0][i].s_clef = clefcode (nextvischar ());
	staffv[0][i].s_key_offset = readint ();
	staffv[0][i].s_octv = readint ();
	staffv[0][i].s_instrument = textp;
	while ((c = nextvischar ()) != '"');
	while ((c = nextchar ()) != '"')
	    *textp++ = c;
	if (staffv[0][i].s_instrument == textp)
	    staffv[0][i].s_instrument = 0;
	else
	    *textp++ = 0;
	staffv[0][i].s_join_down = readint ();
	if (nextvischar () != ';')
	    backup ();
    }
 /* per part */
    n_parts = readint ();
    for (i = 0; i < n_parts; i++) {
	partv[i].pt_end_stave = readint ();
				/* which staff for this part */
	partv[i].pt_updown = readint ();
				/* this part up, down or either */
    }
 /* root */
    getkey ();
    piecev.p_root = key_now;
    prev_key = piecev.p_root - 8;
 /* n_bars */
    piecev.p_bars = readint ();
 /* timesig */
    gettimesig ();
    piecev.p_tsig_n = tsig_n_now;
    piecev.p_tsigd = tsig_d_now;
 /* inter stave gap */
    i_stave_gap = readint ();
    i_staff_gap = readint ();
 /* verbisoty of monitor output */
    i = readint ();
    if (i)
	get_monitor = i;
    i = readint ();
    if (i)
	set_monitor = i;
    i = readint ();
    if (i)
	put_monitor = i;
 /* format */
    hgap = readint ();
    height = readint ();
    reduction = 2400 / height;
    width = readint ();
    page_width = width_now = (1.0 * width * reduction) / 100;
    scale_ht = height * 1.0 / HEIGHT;
 /* transpose chords */
    chordtransp = readint ();
 /* up-down borderline for sticks */
    up_down_border = readint ();
 /* bars-per-stave */
    piecev.p_bps = barv[0].b_bps = bps_now = readint ();
 /* b_sig */
    clefsig = readint ();
    keysig = readint ();
    timesig = readint ();
    leadsig = readint ();
    nat_mode = readint ();
    if ( testing == 0 )
	testing = readint ();
    else
	readint ();
    beamslope = readint ();
    tieform = readint ();
    if (tieform == 1)
	splines = "line";
    else
	if (tieform == 2)
	    splines = "spline";
}

bartype (c) char    c;		/* codes for different bar endings */
{
    int     i = 0;
    while (barlv[i].letter != '*' && barlv[i].letter != c)
	i++;
    if (barlv[i].letter == '*')
	i = BLPLAIN;
    return i;
}

gettimesig () {
    tsig_n_now = readint ();
    tsig_d_now = readint ();
    piecev.p_bar_length = SBL / tsig_d_now * tsig_n_now;
}

getkey () {
    key_now = nextvischar () - 'a';
    piecev.p_key = scale[key_now][0];
}

getclef () {
    int     staff = readint ();
    clef_now = clefs_now[staff] = barv[bar].b_clef[staff] =
	clefcode (nextvischar ());
}

clefcode (c) char   c;
{
    switch (c) {
	case 't': 
	    return TREBLE;
	case 'b': 
	    return BASS;
	case 's': 
	    return SOPRANO;
	case 'a': 
	    return ALTO;
	case 'n': 
	    return TENOR;
    }
    ioerror ("Invalid clef code \"%c\"", c, 0);
    return TREBLE;
}

clearbar (bar, beat) {
    int     p;
    struct bars *barp = barv + bar;
    barp -> b_first_note = beat;
    barp -> b_last_note = -1;
    barp -> b_x_wrt_staff = 0;
    barp -> b_nnotes = 0;
    barp -> b_length = 0;
    barp -> b_new_stave = 0;
    barp -> b_width = 0;
    barp -> b_s_width = 0;
    barp -> b_note_start = 0;
    barp -> b_bps = 0;
    barp -> b_n_tsig = 0;
    barp -> b_d_tsig = 0;
    barp -> b_key = 0;
    barp -> b_root = 0;
    barp -> b_miny = 0;
    barp -> b_maxy = 0;
    barp -> b_end_type = 0;
    for (p = 0; p < NSTAFFS; p++) {
	barp -> b_yover[p] = 0;
	barp -> b_yunder[p] = 0;
	barp -> b_tover[p] = 0;
	barp -> b_tunder[p] = 0;
	barp -> b_clef[p] = 0;
    }
    for (p = 0; p < n_parts; p++) {
	b_lengthpp[p] = 0;
	barp -> b_part_start[p] = 0;
    }
}

struct barls    barlv[] = {
 /* offset, 3*{from, width}, atomno, letter */
     /* dummy */ 0, 0, 1, 0, 0, 0, 0, BARLINE, -1,
     /* simple */ 0, 0, 1, 0, 0, 0, 0, BARLINE, 'S',
     /* double */ 3, 0, 1, 3, 1, 0, 0, DBARLINE, 'D',
     /* thinthick */ 5, 0, 1, 3, 3, 0, 0, THICKLINE, 'T',
     /* thickthin */ 5, 0, 3, 5, 1, 0, 0, KNLINE, 'V',
     /* thin thick thin */ 8, 0, 1, 3, 3, 8, 1, NKNLINE, 'U',
     /* repeat */ 5, 0, 1, 3, 3, 0, 0, REPEAT, 'R',
     /* repeat at left */ 9, 0, 3, 5, 1, 0, 0, REPSTLINE, 'P',
     /* double sided repeat */ 12, 0, 1, 3, 3, 8, 1, DREPLINE, 'Q',
     /* thickthin for lh */ 8, 0, 4, 6, 1, 8, 1, 0, '.',
     /* dashed */ 0, 0, 1, 0, 0, 0, 0, BARLINE, 'H',
     /* dummy */ 0, 0, 0, 0, 0, 0, 0, BARLINE, '*'
};
