#include "pre_mus.h"

char   *idens[] = {
    "title",			/* 0 */
    "root",
    "key",
    "bars",
    "timesig",
    "leadin",
    "hgap",
    "height",
    "width",
    "transpose",
    "pt_updown",		/* 10 */
    "bps_now",
    "bps",
    "sig",
    "accid",
    "octave",
    "staves",
    "parts",
    "clef",
    "autobeam",
    "keyout",			/* 20 */
    "outkey",
    "keyin",
    "inkey",
    "rtitle",
    "chords",			/* 25 */
    "text",
    "reset",
    "barno",
    "partno",
    "sticks",			/* 30 */
    "isg",
    "natural",
    "ctitle",
    "ltitle",
    "test",			/* 35 */
    "beamslope",
    "splines",
    "tune",
    0
};

char    keyword[20];

getword () {
    char    c,
           *p = keyword,
          **q = idens;
    c = nextvischar ();
    if (c == '.')
	return - 1;
    if (c != 'n')		/* make "n_bars" into "bars" */
	*p++ = c;
    while ((c = nextvischar ()) >= 'a' && c <= 'z')
	*p++ = c;
    *p++ = 0;
 /* equals sign is optional */
    if (c != '=')
	backup ();
 /* look it up in table */
    while (*q && strcmp (keyword, *q))
	q++;
    if (*q) {			/* keyword found */
	return q - idens;
    }
    return - 2;
}

getparams (b) {			/* complete reset if b == 2 */
 /* from pushed input if b == 1 */
    int     i,
            j,
            t1,
            t2,
            t3,
            newbar;
    char    newkey = 0;
    struct notes   *notep = notev + beat;
    char    c;
    if (verbose == 2)
	fprintf (stderr, "Enter getparams bar %d param %d\n", bar, b);
    if (b > 1) {
	piecev.left_title = 0;
	piecev.right_title = 0;
	piecev.centre_title = 0;
	bps_now = 0;
	clearaccid ();
	new = 1;
	reset = 0;
	part = 0;
	if (verbose == 2) {
	    fprintf (stderr, "Complete Reset b %d c:", bar);
	    for (i = 0; i < n_staffs; i++)
		fprintf (stderr, "%c,", barv[bar].b_clef[i]);
	    fprintf (stderr, " r:%d k:%c t:%d,%d n:%d\n",
		    barv[bar].b_root,
		    barv[bar].b_key,
		    barv[bar].b_n_tsig,
		    barv[bar].b_d_tsig,
		    barv[bar].b_bps);
	}
    }
    c = nextvischar ();
    if (c == '.')
	return;
    backup ();
    do {
	i = getword ();
	if (verbose == 2 && i >= 0)
	    fprintf (stderr, "Found keyword %d %s\n", i, idens[i]);
	if (i < -1)
	    fprintf (stderr, "Cant find keyword %s\n", keyword);
	switch (i) {
	    case -1: 		/* just a dot */
		c = '.';
		break;
	    case 0: 		/* left_title */
	    case 34: 
	    case 24: 		/* right left_title */
	    case 33: 		/* centre_title */
		if (i == 24)
		    piecev.right_title = textp;
		else
		    if (i == 33)
			piecev.centre_title = textp;
		    else
			piecev.left_title = textp;
		c = nextvischar ();
		while (c == UTEXTSYM) {
		    while ((c = nextchar ()) != UTEXTSYM) {
			if (c == ESCAPE) {
			    c = nextchar ();
			    if (c == 'n')
				c = '\n';
			    else
				if (c != UTEXTSYM)
				    *textp++ = ESCAPE;
			}
			*textp++ = c;
		    }
		    *textp++ = '\n';
		    c = nextvischar ();
		}
		textp--;
		*textp++ = 0;
		backup ();
		if (verbose && i == 0)
		    fprintf (stderr, "Title: %s\n", piecev.left_title);
		break;
	    case 1: 		/* root */
	    case 2: 		/* key */
	    case 22: 		/* keyin */
	    case 23: 		/* inkey */
		getkey ();
		if (i == 1 || i == 2) {/* key, set both in and out */
		    if (b == 1)
			fprintf (stderr, "Resetting input key on .MS line?\n");
		    newkey = 1;
		    if (part == 0) {
			root_now += keyoffset;
			octv_now += octvoffset;
			if (root_now >= 21)
			    root_now -= 12;
			if (root_now < 0)
			    root_now += 12;
			barv[bar].b_root = root_now;
			barv[bar].b_key = key_now;
			if (b) {
			    piecev.p_root = root_now;
			    piecev.p_key = key_now;
			    piecev.p_octv = octv_now;
			}
		    }
		}
		if (verbose == 3)
		    fprintf (stderr, "Bar %d new root %d key %c\n",
			    bar, root_now, key_now);
		break;
	    case 3: 		/* n_bars */
		piecev.p_bars = readint ();
		break;
	    case 4: 		/* timesig */
		gettimesig ();
		if (b) {
		    piecev.p_tsig_n = tsig_n_now;
		    piecev.p_tsigd = tsig_d_now;
		}
		if (verbose == 3)
		    fprintf (stderr, "Bar %d tsig_n %d tsigd %d\n",
			    bar, piecev.p_tsig_n, piecev.p_tsigd);
		break;
	    case 5: 		/* p_lead_notes */
		piecev.p_lead_notes = readint ();
		break;
	    case 6: 		/* hgap */
		hgap = readint ();
		break;
	    case 7: 		/* stave height */
		height = readint ();
		break;
	    case 8: 		/* stave width */
		width_now = readint ();
		if (width_now == 0)
		    width_now = width;
		if (b) {
		    width = width_now;
		}
		barv[bar].b_s_width = width_now;
		break;
	    case 9: 		/* transpose */
		keyoffset = readint ();
		root_now += keyoffset;
		piecev.p_root += keyoffset;
		c = nextvischar ();
		backup ();
		if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
		    octvoffset = readint ();
		    octv_now += octvoffset;
		    piecev.p_octv += octvoffset;
		}
		break;
	    case 10: 		/* up_down_border */
		up_down_border = readint ();
		break;
	    case 11: 
	    case 12: 		/* bps_now */
		barv[bar].b_bps = bps_now = readint ();
		if (b)
		    piecev.p_bps = bps_now;
		break;
	    case 13: 		/* sig */
		clefsig = keysig = timesig = leadsig = 0;
		while (notterm (c = nextvischar ()))
		    switch (c) {
			case 'c': 
			    clefsig = CLEFSIG;
			    break;
			case 'k': 
			    keysig = KEYSIG;
			    break;
			case 't': 
			    timesig = TIMESIG;
			    break;
			case 'l': 
			    leadsig = LEADSIG;
			    break;
			default: 
			    ioerror ("Invalid sigflag \"%c\" in header", c, 0);
		    }
		barv[bar].b_sig = clefsig + timesig + keysig + leadsig;
		backup ();
		break;
	    case 14: 		/* n_accids */
		c = nextvischar ();
		switch (c) {
		    case 'a': 
			accid_mode = AUTOACCID;
			break;
		    case 's': 
			accid_mode = SEMIACCID;
			break;
		    case 'e': 
			accid_mode = EXPLACCID;
			break;
		    default: 
			ioerror ("Invalid n_accid code %c", c, 0);
		}
		break;
	    case 15: 		/* default octv */
		c = nextvischar ();
		switch (c) {
		    case 'c': 
			octv_mode = COCTAVE;
			break;
		    case 's': 
			octv_mode = STAVEOCTAVE;
			break;
		    case 'k': 
			octv_mode = KEYOCTAVE;
			break;
		    case 'p': 
			octv_mode = PREVOCTAVE;
			break;
		    default: 
			ioerror ("Invalid octv code %c", c, 0);
		}
		break;
	    case 16: 		/* staves */
		if ((c = nextvischar ()) >= '0' && c <= '9') {
		    backup ();
		    n_staves = readint ();
		}
		else {
		    backup ();
		    n_staves = 0;
		}
		i = 0;
		while (notterm (c = nextvischar ())) {
		    barv[bar].b_clef[i] = clefs_now[i] = staffv[0][i].s_clef = c;
		    if (c != 't' && c != 'b' && c != 's' && c != 'a' && c != 'n')
			ioerror ("Invalid clef code \"%c\" for stave %d",
				c, i + 1);
		    c = nextvischar ();
		    if (c == '+' || c == '-') {
			staffv[0][i].s_key_offset =
			    c == '+' ? readint () : -readint ();
			c = nextvischar ();
		    }
		    if (c == HIGHER || c == LOWER) {
			while (c == HIGHER || c == LOWER) {
			    if (c == HIGHER)
				staffv[0][i].s_octv++;
			    if (c == LOWER)
				staffv[0][i].s_octv--;
			    c = nextvischar ();
			}
		    }
		    staffv[0][i].s_instrument = 0;
		    if (c == '"') {
			staffv[0][i].s_instrument = textp;
			while ((c = nextchar ()) != '"')
			    *textp++ = c;
			*textp++ = 0;
			c = nextvischar ();
		    }
		    staffv[0][i].s_join_down = (c == '=');
		    if (!staffv[0][i].s_join_down)
			backup ();
		    i++;
		}
		if (n_staves && n_staves != i)
		    ioerror ("Number of staves wrong, given %d, actual %d", n_staves, i);
		n_staffs = n_staves = i;
		if (n_staves > NSTAVES)
		    ioerror ("Too many staves, max is %d", NSTAVES, 0);
		backup ();
		break;
	    case 17: 		/* parts */
		parts_ignored = 0;
		n_parts = 0;
		i = 0;
		while (notterm (c = nextvischar ())) {
		    backup ();
		    j = partv[i].pt_end_stave = readint () - 1;
		    c = nextvischar ();
		    if (c >= '0' && c <= '9') {
			n_parts = j + 1;
			backup ();
			j = partv[i].pt_end_stave = readint () - 1;
			c = nextvischar ();
		    }
		    if (n_staves && (j < -1 || j >= n_staves)) {
			ioerror ("Part no %d, invalid stave number %d",
				i + 1, j + 1);
			partv[i].pt_end_stave = 0;
		    }
		    partv[i].pt_updown =
			c == 'u' ? 1 : c == 'd' ? -1 : 0;
		    if (partv[i].pt_ignore = c == 'i' || partv[i].pt_end_stave == -1) {
			parts_ignored++;
			partnos[i] = -1;
		    }
		    else {
			partnos[i] = i - parts_ignored;
		    }
		    i++;
		}
		if (n_parts && n_parts != i)
		    ioerror ("No of parts inconsistent %d %d", n_parts, i);
		n_parts = i;
		if (n_parts > NPARTS)
		    ioerror ("Too many parts, max is %d", NPARTS, 0);
		backup ();
		break;
	    case 18: 		/* clef */
		barv[bar].b_clef[partv[part].pt_end_stave] = clef_now = nextvischar ();
		break;
	    case 19: 		/* autobeam */
		c = nextvischar ();
		backup ();
		if (c >= '0' && c <= '9')
		    autobeam = readint ();
		else
		    autobeam = -1;
		break;
	    case 20: 		/* keyout */
	    case 21: 		/* outkey */
		t1 = key_now;
		t2 = root_now;
		t3 = piecev.p_beat_length;
		getkey ();
		if (part == 0) {
		    root_now += keyoffset;
		    octv_now += octvoffset;
		    if (root_now >= 21)
			root_now -= 12;
		    if (root_now < 0)
			root_now += 12;
		    barv[bar].b_key = key_now;
		    barv[bar].b_root = root_now;
		    if (b) {
			piecev.p_key = key_now;
			piecev.p_root = root_now;
			if (verbose == 2)
			    fprintf (stderr,
				    "Bar %d root %d\n", bar, root_now);
		    }
		}
		key_now = t1;
		root_now = t2;
		piecev.p_beat_length = t3;
		break;
	    /* 22 and 23 are keyin, inkey */
	    /* 24 is right_title */
	    case 25: 		/* interpret chord names */
		chordtransp = 1;/* over or under */
		if (c = nextvischar (), c == 'o' || c == 'u') {
		    chordtransp = c == 'u' ? 1 : -1;
		}
		else
		    backup ();
		break;
	    case 26: 		/* suppress text */
		textunder = textover = 0;
		while ((c = nextvischar ()) == 'o' || c == 'u')
		    if (c == 'o')
			textover = 1;
		    else
			if (c == 'u')
			    textunder = 1;
		backup ();
		break;
	    case 27: 		/* reset */
		fprintf (stderr, "\"reset\" is a withdrawn facility\n");
		abandon (1);
		if (bar == 0)
		    break;
		if (piecev.p_bars != reset - 1) {
		    if (verbose)
			fprintf (stderr,
				"****** Warning : No of bars given before \\reset is %d; actual %d ******\n",
				piecev.p_bars, reset - 1);
		    piecev.p_bars = reset - 1;
		}
		if (verbose == 3)
		    fprintf (stderr, "No of bars so far %d; notes so far %d\n",
			    bar, beat);
		putpiece ();
		piecev.left_title = 0;
		piecev.right_title = 0;
		clearaccid ();
		new = 1;
		reset = 0;
		for (i = 0; i < n_staffs; i++)
		    barv[bar].b_clef[i] = clefsig ? clefs_now[i] : 0;
		if (part == 0) {
		    if (b) {
			piecev.p_key = key_now;
			piecev.p_root = root_now;
			piecev.p_tsig_n = tsig_n_now;
			piecev.p_tsigd = tsig_d_now;
		    }
		    barv[bar].b_key = keysig ? key_now : 0;
		    barv[bar].b_root = keysig ? root_now : 0;
		    barv[bar].b_n_tsig = timesig ? tsig_n_now : 0;
		    barv[bar].b_d_tsig = timesig ? tsig_d_now : 0;
		    barv[bar].b_bps = bps_now;
		}
		if (verbose == 1 ) {
		    fprintf (stderr, "reset %d c:", bar);
		    for (i = 0; i < n_staffs; i++)
			fprintf (stderr, "%c,", barv[bar].b_clef[i]);
		    fprintf (stderr, " k:%d t:%d,%d n:%d\n",
			    barv[bar].b_key,
			    barv[bar].b_n_tsig,
			    barv[bar].b_d_tsig,
			    barv[bar].b_bps);
		}
		part = 0;
	    /* 	   timesig = 0; */
		break;
	    case 28: 		/* barno */
		newbar = getbarno ();
		if (newbar < bar) {/* go back to earlier bar */
		    bar = newbar;
		    reset = bar;
		    if (verbose == 1)
			fprintf (stderr, "Barno reset back to %d\n", bar);
		    break;
		}
		else {		/* advance, fill in with rests */
		    notep = notev + beat;
		    for (; bar < newbar; bar++) {
			if ( verbose == 1)
	fprintf( stderr, "part %d bar %d beat %d\n", part, bar, beat );
			bar_first_note[bar][part] = beat;
			bar_last_note[bar][part] = beat + 1;
			notep -> n_pitch = RESTSYM;
			notep -> n_octv = '0';
			barv[ bar ].b_length =
			notep -> n_length = piecev.p_bar_length;
			notep -> n_part = part;
			notebar[beat] = bar;
			beat++;
			notep++;
/*			  barv[bar].b_end_type = 0;
			for (i = 0; i < NSTAFFS; i++) {
			    barv[bar].b_tover[i] = 0;
			    barv[bar].b_clef[i] = 0;
			}
			barv[bar].b_length = piecev.p_bar_length;
			reset++; */
		    }
		    bar_first_note[bar][part] = beat;
		}
		break;
	    case 29: 		/* partno */
		part = readint () - 1;
		if (part < 0 || part >= n_parts) {
		    ioerror ("Invalid part no %d in bar %d", part, bar);
		    part = 0;
		}
		checklength ();
		if (bar_first_note[bar][part] == 0)
		    bar_first_note[bar][part] = beat;
		break;
	    case 30: 		/* sticks */
		switch (nextvischar ()) {
		    case 'u': 
			pt_updown = 1;
			break;
		    case 'd': 
			pt_updown = -1;
			break;
		    default: 
			pt_updown = 0;
			break;
		}
		break;
	    case 31: 		/* isg = interstave gap */
		i_stave_gap = (int) (1.0 * readint () * reduction / 100);
		if (notterm (nextvischar ())) {
		    backup ();
		    i_staff_gap = (int) (1.0 * readint () * reduction / 100);
		}
		else
		    backup ();
		break;
	    case 32: 		/* natural mode */
		nat_mode = readint ();
		break;
	    case 35: 		/* test */
		testing = readint ();
		break;
	    case 36: 		/* formula for beam slope */
		beamslope = readint ();
		break;
	    case 37: 		/* spline or line */
		tieform = readint ();
		break;
	    default: 
		ioerror ("Invalid keyword \"%s\" in header", keyword, 0);
	}
	c = nextvischar ();
	if (notterm (c)) {
	    ioerror ("Invalid text in header", 0, 0);
	    while (notterm (c = nextvischar ()))
		fprintf (stderr, "%c", c);
	    fprintf (stderr, "\n******\n");
	}
    }
    while (c != '.');
    if (newkey && octv_mode == STAVEOCTAVE) {
	if ('c' <= key_now && key_now <= 'e') {
	    octv_now++;
	    if (b)
		piecev.p_octv++;
	}
    }
}

notterm (c) {			/* c is not a terminator */
    return c != '.' && c != ';';
}

getkey () {
    char    pitch,
            ch1,
            ch2;
    root_now = 8;		/* key of C */
    key_now = 'c';
    octv_now = '5';		/* default octv */
    piecev.p_beat_length = SBL / piecev.p_tsigd;
    ch1 = nextvischar ();
    if (ch1 >= 'A' && ch1 <= 'G') {
	ch1 += 'a' - 'A';
    }
    key_now = ch1;
    if (ch1 >= 'a' && ch1 <= 'g') {
	ch2 = nextvischar ();
	if (ch2 != SHARPSYM && ch2 != FLATSYM) {
	    pitch = note_to_int (ch1, ' ');
	    backup ();
	}
	else {			/* sharp or flat given */
	    pitch = note_to_int (ch1, ch2);
	}
    }
    else
	ioerror ("Invalid key \"%c\" in header", ch1, 0);
    clearaccid ();
    ch1 = ch2;
    if (ch1 == 'm') {		/* minor key */
	pitch -= 3;
	key_now += key_now == 'g' ? -5 : 2;
	ch1 = nextvischar ();
    }
    root_now = pitch;
    while ((ch1 = nextvischar ()) == HIGHER)
	octv_now += 1;
    backup ();
    while ((ch1 = nextvischar ()) == LOWER)
	octv_now -= 1;
    backup ();
    while ((ch1 = nextvischar ()) == SHORTER)
	piecev.p_beat_length /= 2;
    backup ();
    while ((ch1 = nextvischar ()) == LONGER)
	piecev.p_beat_length *= 2;
    backup ();
}
