// tropt.js - module to optimize the notes after transposition
//
// Copyright (C) 2022-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// abc2svg is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with abc2svg.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%tropt" appears in a ABC source.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.tropt = {

    // function called before start of the generation
    voice_adj: function(of, last_s) {
	if (last_s) {			// if not first time
		of(last_s)
		return
	}
    var	v, p_v, s, m, nt, p, a, np, na,
	C = abc2svg.C,
	vo_tb = this.get_voice_tb(),
	nv = vo_tb.length

	// check if some next note has the same pitch without any accidental
	function ok(s, p) {
	    var	nt, m

		while (s) {
			if (s.bar_type)
				return 1 //true
			if (s.type == C.NOTE) {
				for (m = 0; m <= s.nhd; m++) {
					nt = s.notes[m]
					if (nt.pit == p)
						return nt.acc
				}
			}
			s = s.next
		}
		return 1 //true
	} // ok()

	for (v = 0; v < nv; v++) {
		p_v = vo_tb[v]
		if (!p_v.tropt || !p_v.ckey.k_none || !p_v.tr_sco)
			continue
		for (s = p_v.sym; s; s = s.next) {
			if (s.type != C.NOTE)
				continue
			for (m = 0; m <= s.nhd; m++) {
				nt = s.notes[m]
				if (nt.tie_s) {		// if end of tie
					nt.pit = nt.tie_s.pit
					continue
				}
				p = nt.pit % 7		// A..G
				a = nt.acc
				na = 3
				switch (a) {
				case -1:
					switch (p) {
					case 2:		// C
					case 5:		// F
						break	
					default:
						continue
					}
					np = nt.pit - 1
					break
				case -2:
					switch (p) {
					case 2:		// C
					case 5:		// F
						na = -1
						break
					}
					np = nt.pit - 1
					break
				case 1:
					switch (p) {
					case 1:		// B
					case 4:		// E
						break	
					default:
						continue
					}
					np = nt.pit + 1
					break
				case 2:
					switch (p) {
					case 1:		// B
					case 4:		// E
						na = 1
						break	
					}
					np = nt.pit + 1
					break
				default:
					continue
				}
				if (ok(s, np)) {
					nt.pit = np
					nt.acc = na
					if (p_v.map)
						this.set_map(p_v, nt, na)
				}
			}
		}
	}
	of(last_s)
    }, // voice_adj()

    // set the tropt parameter
    do_pscom: function(of, text) {
	if (text.indexOf("tropt ") == 0)
		this.set_v_param("tropt", text.split(/[ \t]/)[1])
	else
		of(text)
    }, // do_pscom()

    // set the tropt parameter in the current voice
    set_vp: function(of, a) {
    var	i,
	curvoice = this.get_curvoice()

	for (i = 0; i < a.length; i++) {
		if (a[i] == "tropt=") {
			curvoice.tropt = this.get_bool(a[i + 1])
			break
		}
	}
	of(a)
    }, // set_vp()

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.tropt.do_pscom.bind(abc, abc.do_pscom)
	abc.voice_adj = abc2svg.tropt.voice_adj.bind(abc, abc.voice_adj)
	abc.set_vp = abc2svg.tropt.set_vp.bind(abc, abc.set_vp)
    }
} // tropt

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.tropt = abc2svg.tropt.set_hooks