#include "post_mus.h"

extern int  textunderend,
            textoverend;


#define BOVERHEAD    2
spreadbars (stave, bps) {	/* spreadbars bars on current stave */
 /* if bps == 0, don't spread, else fill to n_bars / bps * width */
    struct staves  *stavep = stavev + stave;
    struct bars *barp = barv;
    int     first = stavep -> s_first_bar,
            last = stavep -> s_last_bar;
    int     n_bars = last - first;/* actual number of bars */
    int     start = bar0start;	/* offset */
    int     usewidth = width_now - start;/* usable width */
    int     previous = width_now;/* RH end of next bar */
    int	    totb_width = 0,
	    totb_length = 0,
            b_length = 0,
            totjunk = 0,
            junk = 0;
    int     bar;
    int     posn;
    if (bps == 0) return;

    usewidth = usewidth * n_bars / bps;
    previous = start + usewidth;
    for (bar = first, barp = barv + first; bar < last; bar++, barp++) {
	barp -> b_x_wrt_staff = totb_width + bar0start;
	totb_width += barp -> b_width;
	totb_length += barp -> b_length + BOVERHEAD;
	totjunk += barp -> b_note_start
	    + atom[barlv[barp -> b_end_type].atomno].a_width
	    + atom[barlv[barp -> b_stt_type].atomno].a_width;
	if (set_monitor == 10)
	    barprint (bar);
    }
    if (stavep -> s_x_right >= previous)
	return;
    if (set_monitor == 1)
	fprintf (stderr, "Spread (%d,%d-1)=%d bars from width %d(%d) to %d(%d) (%d%%)\n",
		first, last,
		n_bars,
		convert (stavep -> s_x_right), stavep -> s_x_right,
		convert (previous), previous,
		percent (convert (stavep -> s_x_right), convert (previous))
	    );
    b_length = totb_length;
    junk = totjunk;
    usewidth -= totjunk;
    stavep -> s_x_right = previous;
    for (bar = last - 1, barp = barv + last - 1; bar >= first; bar--, barp--) {
	b_length -= barp -> b_length + BOVERHEAD;
	junk -= barp -> b_note_start
	    + atom[barlv[barp -> b_end_type].atomno].a_width
	    + atom[barlv[barp -> b_stt_type].atomno].a_width;
	posn = start + junk + (int) (1.0 * b_length * usewidth / totb_length);
	if (barp -> b_x_wrt_staff < posn) {/* can move it right */
	    if (previous - posn > barp -> b_width) {/* fits OK */
		barp -> b_x_wrt_staff = posn;
	    }
	    else
		if
		    (barp -> b_x_wrt_staff < previous - barp -> b_width) {
				/* move partway */
		    barp -> b_x_wrt_staff = previous - barp -> b_width;
		}
	}			/* else don't move it */
	barp -> b_width = previous - barp -> b_x_wrt_staff;
	previous = barp -> b_x_wrt_staff;
	spreadnotes (bar);
    }
    if (set_monitor == 10)
	for (bar = first, barp = barv + first; bar < last; bar++, barp++)
	    barprint (bar);
}

#define NOVERHEAD    1
spreadnotes (bar) {		/* spread notes within bar */
    struct  bars *barp = barv + bar;
    int     first = barp -> b_first_note;/* first note */
    int     last = barp -> b_last_note;/* last note + 1 */
    int     empty = last <= first;
    struct  notes   *notep = notev + first;
    int     start = barp -> b_note_start;/* x co-ord of first note */
    int     avail_width =
	    barp -> b_width - start
	    - atom[barlv[barp -> b_end_type].atomno].a_width - hgap;
    int     previous = avail_width + start;/* dummy end note */
    int     note,
            posn,
            pt;
    int	    offset,
	    delta;		/* squeeze if more notes */
    int     tothdsq = barp -> b_length,
            hdsq = barp -> b_length;
    int     spare =
            avail_width + start
    -	    (empty ? 0
	    : notev[last - 1].n_x_wrt_bar + notev[last - 1].n_width);
    int     accid_off,
	    maxnpp, /* maximum notes per part */
	    i;
    int     part = notev[last - 1].n_part;

 /* if no notes, abandon */
    if (empty) {
	if (set_monitor == 3)
	    fprintf (stderr, "empty bar %d to spread\n", bar);
	return;
    }

 /* if max of one note per part, centre it */
    maxnpp = 0;
    for (pt = 0; pt < n_parts; pt++) {
	i = 0;
	for (note = first; note < last; note++) {
	    if (notev[note].n_part == pt)
		i++;
	}
	if ( maxnpp < i ) maxnpp = i;
    }
    if (maxnpp < 2) {
	for (; first < last; first++, notep++) {
	    posn = start + (avail_width - notep -> n_width) / 2;
	    if (notep -> n_x_wrt_bar < posn)
		notep -> n_x_wrt_bar = posn;
	}
	if (set_monitor == 3)
	    fprintf (stderr, "bar %d single note posn %d\n", bar, posn );
	return;
    }

 /* a little extra space before first note */
    if (last > first) {
	delta = spare / (maxnpp + 3);
	if (notev[first].stickup >= 0)/* no stick or stick up */
	    delta /= 2;
	start += delta;
	avail_width -= delta;
	previous = avail_width + start;/* dummy end note */
    }

 /* mustn't compress less than text allows */
    textoverend = textunderend = previous;

    for (note = last - 1; note >= first; note--) {
	notep = notev + note;
	if (set_monitor == 11)
	    noteprint (note);
    /* if new part, reset as for complete bar */
	if (notep -> n_part != part) {
	    part = notep -> n_part;
	    hdsq = tothdsq;
	    previous = start + avail_width;
	}
    /* desired position */
	hdsq -= notep -> n_length;
	if (notep -> n_length == tothdsq && notep -> n_pitch == RESTSYM) {
	    posn = start + (avail_width - notep -> n_width) / 2;
	}
	else {
	    posn = start + avail_width * hdsq / tothdsq;
	}
	if (notep -> n_accid != ' ') {/* position blob at desired posn */
	    accid_off = atom[
		    notep -> n_accid == '+' ? SHARP :
		    notep -> n_accid == '-' ? FLAT :
		    notep -> n_accid == '=' ? NATURAL : 0
		].a_width;
	    posn -= accid_off;
	    notep -> n_x_stick += accid_off;/* is this a bodge? */
	}
	offset = notep -> n_x_wrt_bar;
	if (posn > offset) {
	    if (posn + notep -> n_width + hgap < previous) {/* fits OK */
		notep -> n_x_wrt_bar = posn;
	    }
	    else
		if (offset < previous - notep -> n_width - hgap) {
		/* move partway */
		    notep -> n_x_wrt_bar = previous - notep -> n_width - hgap;
		}		/* else can't move it at all */
	}
	previous = notep -> n_x_wrt_bar;
    } /* for note = last downto first */
    if (set_monitor == 11)
	for (note = last - 1; note >= first; note--)
	    noteprint (note);
}

convert (length) {		/* convert by scale factor */
    return (int) ((length * 100.0 + reduction / 2) / reduction);
}

percent (n, d) {
    return (int) ((n * 100.0) / d);
}
