// diag.js - module to insert guitar chord diagrams
//
// Copyright (C) 2018-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 "%%diagram" or "%%setdiag" appear in a ABC source.
//
// The command %%diagram draws a chord diagram above the chord symbols.
//
// Parameters
//	%%diagram [ <#diagram> | 0 ]
// with
//	<#diagram> identifier of the diagram type (number)
//	('1' is for the 6 strings guitar)
//
// The command %%setdiag defines the chord diagram of a chord symbol
//	for the current diagram type.
//
// Parameters
//	%%setdiag <chord> <dots> <label[,pos]> <fingers> [barre=<num>-<num>]
// with
//	<chord> = chord symbol
//	<dots>  = list of diagram offset of dots on the strings - '0 or 'x': no dot
//	<label> = text to write on the left of the <pos>th fret
//				(<pos> default = 1, fret #0 is no text)
//	<fingers> = finger numbers ou 'x' (mute) or '0'/'y' (no finger)
//	barre=<num>-<num> draw a bar between the two string numbers in the first fret
//				(numbering order 654321 for E,A,D,GBe)

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

abc2svg.diag = {

    cd4: {},
// common diagrams by Guido Gonzato from http://www.guitar-chord.org/ (2021-08-27)
    cd6: {
	C: "x32010 ,0 x32010",
	Cm: "x03320 fr3 x03420 barre=5-1",
	C7: "x32310 ,0 x32410",
	Cm7: "003020 fr3 x03020 barre=5-1",
	CM7: "032000 ,0 x21000",
	Csus4: "x03340 fr3 x02340 barre=5-1",
	D: "000232 ,0 x00132",
	Dm: "000231 ,0 x00231",
	D7: "000212 ,0 x00312",
	Dm7: "000211 ,0 xx0211",
	DM7: "000222 ,0 xx0111",
	Dsus4: "000233 ,0 xx0134",
	E: "022100 ,0 023100",
	Em: "022000 ,0 023000",
	E7: "020100 ,0 020100",
	Em7: "022030 ,0 023040",
	EM7: "021100 ,0 031200",
	Esus4: "022200 ,0 023400",
	F: "033200 fr1 034200 barre=6-1",
	Fm: "033000 fr1 034000 barre=6-1",
	F7: "030200 fr1 030200 barre=6-1",
	Fm7: "030000 fr1 030000 barre=6-1",
	FM7: "xx3210 ,0 xx3210",
	Fsus4: "033300 fr1 023400 barre=6-1",
	G: "320003 ,0 230004",
	Gm: "033000 fr3 034000 barre=6-1",
	G7: "320001 ,0 320001",
	Gm7: "030000 fr3 030000 barre=6-1",
	GM7: "320002 ,0 310002",
	Gsus4: "033300 fr3 023400 barre=6-1",
	A: "002220 ,0 002340",
	Am: "002210 ,0 002310",
	A7: "002020 ,0 002030",
	Am7: "002010 ,0 002010",
	AM7: "002120 ,0 x02130",
	Asus4: "x02230 ,0 x02340",
	B: "x03330 fr2 002340 barre=5-1",
	Bm: "x03320 fr2 003410 barre=5-1",
	B7: "021202 ,0 x21304",
	Bm7: "003020 fr2 x03020 barre=5-1",
	BM7: "003230 fr2 x03240 barre=5-1",
	Bsus4: "x03340 fr2 x02340 barre=5-1",
    }, // cd6{}

// function called before tune generation
    draw_gchord: function(of, i, s, x, y) {
    var	gch, nm,
	cfmt = this.cfmt(),
	n = cfmt.diag,				// number of strings
	glyphs = this.get_glyphs()

	// create the base decorations if not done yet
	if (!glyphs.ddot) {
		this.add_style("\
\n.fng {font:6px sans-serif}\
\n.frn {font:italic 7px sans-serif}")
		glyphs.ddot = '<circle id="ddot" class="fill" r="1.5"/>'
	}

	if (!glyphs["fb" + n]) {
		if (n == 4) {
			glyphs.fb4 = '<g id="fb4">\n\
<path class="stroke" stroke-width="0.4" d="\
M-6 -24h12m0 6h-12\
m0 6h12m0 6h-12\
m0 6h12"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-6 -24v24m4 0v-24\
m4 0v24m4 0v-24"/>\n\
</g>'
			glyphs.nut4 =
				'<path id="nut4" class="stroke" stroke-width="1.6" d="\
M-6.2 -24.5h12.4"/>'
		} else {
			glyphs.fb6 = '<g id="fb6">\n\
<path class="stroke" stroke-width="0.4" d="\
M-10 -24h20m0 6h-20\
m0 6h20m0 6h-20\
m0 6h20"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-10 -24v24m4 0v-24\
m4 0v24m4 0v-24\
m4 0v24m4 0v-24"/>\n\
</g>'
			glyphs.nut6 =
				'<path id="nut6" class="stroke" stroke-width="1.6" d="\
M-10.2 -24.5h20.4"/>'
		}
	}

	// convert the chord symbol to a "better known" one
	function ch_cnv(t) {
	    var	a = t.match(/[A-G][#♯b♭]?([^/]*)\/?/)	// a[1] = chord type
		if (a && a[1]) {
			a[2] = abc2svg.ch_alias[a[1]]
			if (a[2] != undefined)
				t = t.replace(a[1], a[2])
		}
		return t.replace('/', '.')
			.replace(/\u266f/g,'#')
			.replace(/\u266d/g,'b')
	} // ch_cnv()

	// create a glyph of the diagram
	function diag_add(nm) {			// chord name
	    var	dc, i, l, x, y,
		d = abc2svg.diag["cd" + n][nm.slice(1)]
						// definition of the diagram

		if (!d)
			return		// no diagram of this chord
		d = d.split(' ')
		x = 2 - 2 * n
		dc = '<g id="' + nm + '">\n\
<use xlink:href="#fb' + n + '"/>\n'
		l = d[1].split(',')	// label,position
		if (!l[0] || l[0].slice(-1) == l[1])
			dc += '<use xlink:href="#nut' + n + '"/>\n'
		if (l[0])
			dc += '<text x="' + (x - 10).toString()
				+ '" y="' + ((l[1] || 1) * 6 - 25)
				+ '" class="frn">' + l[0] + '</text>\n'
		// fingers
		dc += '<text x="' + (n == 6 ? '-12,-8,-4,0,4,8'
					: '-8,-4,0,4')
				+ '" y="-26" class="fng">'
				+ d[2].replace(/[y0]/g, ' ')
				+ '</text>\n'
		// dots
		for (i = 0; i < n; i++) {
			l = d[0][i]
			if (l && l != 'x' && l != '0')
				dc += '<use x="' + (i * 4 + x)
					+ '" y="' + (l * 6 - 27)
					+ '" xlink:href="#ddot"/>\n'
		}
		// barre
		if (d[3]) {
			l = d[3].match(/barre=(\d)-(\d)/)
			if (l)
				dc += '<path id="barre" class="stroke"\
 stroke-width="1.4" d="M' + ((n - l[1]) * 4 + x - 2)
					+ ' -21h' + ((l[1] - l[2]) * 4 + 4) + '"/>'
		}
		dc += '</g>'
		glyphs[nm] = dc
	} // diag_add()

	// --- draw_gchord ---
	of(i, s, x, y)		// draw the chord symbols and the annotations

	if ((s.invis && s.play)	// play sequence: no chord nor annotation
	 || !n)			// no %%diagram
		return
	gch = s.a_gch[i]
	if (!gch || gch.type != 'g' || gch.capo)
		return
	nm = n + ch_cnv(gch.text)	// glyph name

	// build a glyph if not done yet
	if (!glyphs[nm])
		diag_add(nm)

	// output the diagram above the chord symbol
	if (glyphs[nm]) {
		x = s.x
		y = this.y_get(s.st, 1, x - 10, 20)
		this.xygl(x, y + 2, nm)
		this.y_set(s.st, 1, x - 10, 20, y + 34)
	}
    }, // draw_gchord()

    set_fmt: function(of, cmd, param) {
    var	a, d, n,
	cfmt = this.cfmt()

	switch (cmd) {
	case "diagram":
		n = param
		if (n == '0')
			n = ''
		else if (n != '4')
			n = '6'
		cfmt.diag = n
		return
	case "setdiag":
		n = cfmt.diag
		if (!n)
			n = "6"		// default = 6 strings guitar
		a = param.match(/(\S*)\s+(.*)/)
		if (a && a.length == 3) {
			d = a[2].split(' ')
			if (d && d.length >= 3) {
				abc2svg.diag["cd" + n][a[1].replace('/', '.')]
					= a[2]
				return
			}
		}
		this.syntax(1, this.errs.bad_val, "%%setdiag")
		return
	}
	of(cmd, param)
    },

    set_hooks: function(abc) {
	abc.draw_gchord = abc2svg.diag.draw_gchord.bind(abc,abc.draw_gchord)
	abc.set_format = abc2svg.diag.set_fmt.bind(abc, abc.set_format)
    }
} // diag

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