Questo modulo serve a {{Discendenza}} per la creazione automatica di grafici genealogici.


require('Module:No globals')
local p = {}
local pers = {}
local tabella = {}
local tdg = ''

local function mostra2(pid, idt)
	local ss = idt .. pers[pid].id .. ' => x = ' .. pers[pid].x .. ', sp = ' .. pers[pid].sp .. ', y = ' .. pers[pid].y .. '<br/>'
	for i, v in pairs(pers[pid].figli) do
		ss = ss .. idt .. mostra2(v,idt .. '> ')
	end
	return ss
end

local function dividi(dati)
	local n = 0
	local m = 1
	local err = 0
	local v1 = {}
	for x in string.gmatch(dati,'([^@]+)') do
		n = n+1
		v1[n] = x
	end
	if (4*math.floor(n/4) == n) then
		while (4*m<=n) do
			if ((tonumber(v1[4*m-3])) and (tonumber(v1[4*m-2]))) then
				pers[tonumber(v1[4*m-3])] = { id = tonumber(v1[4*m-3]), padre = tonumber(v1[4*m-2]), testo = v1[4*m-1], nota = v1[4*m], id2 = -1, x = -1, y = -1, sp = 0, figli = {} }
			else
				err = m
			end
			m = m+1
		end
	else
		err = -1
	end
	return err
end

local function organizza(pid, plev)
	pers[pid].y = plev
	if (not tabella[plev]) then
		tabella[plev] = {}
	end
	table.insert(tabella[plev], pid)
	for i, v in pairs(pers[pid].figli) do
		pers[v].id2 = i
		organizza(v, plev+1)
	end
end

local function limSx(pid, delta, dt)
	local tt = dt
	if (tt[pers[pid].y]) then
		tt[pers[pid].y] = math.min(tt[pers[pid].y], pers[pid].x+delta)
	else
		tt[pers[pid].y] = pers[pid].x + delta
	end
	for i, v in pairs(pers[pid].figli) do
		tt = limSx(v, delta+pers[pid].sp, tt)
	end
	return tt
end

local function limDx(pid, delta, dt)
	local tt = dt
	if (tt[pers[pid].y]) then
		tt[pers[pid].y] = math.max(tt[pers[pid].y], pers[pid].x+delta)
	else
		tt[pers[pid].y] = pers[pid].x + delta
	end
	for i, v in pairs(pers[pid].figli) do
		tt = limDx(v, delta+pers[pid].sp, tt)
	end
	return tt
end

local function riallinea(pid2, n1, n2)
	local distanza = n2 - n1
	local vrf = 0
	if (distanza > 1) then
		local dst = (pers[pers[pid2].figli[n2]].x - pers[pers[pid2].figli[n1]].x)/distanza
		local cc = 1
		while (n1+cc < n2) do
			local sposta = pers[pers[pid2].figli[n1]].x + math.floor(cc*dst)
			if (sposta - pers[pers[pid2].figli[n1+cc]].x > 0) then
				pers[pers[pid2].figli[n1+cc]].x = sposta
				pers[pers[pid2].figli[n1+cc]].sp = sposta
			end
			cc = cc + 1
		end
		vrf = 1
	end
	return vrf
end

local function verifica(pid)
	local tSx
	local tDx
	local sposta = 0

	local fine = pers[pid].id2
	local frt = 1
	local frt2, n
	
	while (frt < fine) do
		frt2 = pers[pers[pers[pid].padre].figli[frt]].id
		tDx = limDx(frt2, 0, {})
		tSx = limSx(pid, 0, {})
		n = pers[pid].y
		while ((tSx[n]) and (tDx[n])) do
			if (tSx[n] - tDx[n] + sposta < 2) then
				sposta = 2 + tDx[n] - tSx[n]
				tdg = tdg .. '<br/>Sposta: id = ' .. pid .. ' (' .. pers[pid].x .. ',' .. pers[pid].sp .. '), Sx = ' .. tSx[n]
				tdg = tdg .. '// id2 = ' .. frt2 .. ' (' .. pers[frt2].x .. ',' .. pers[frt2].sp .. '), Dx = ' .. tDx[n]
				tdg = tdg .. '// n = ' .. n .. ', d = ' .. sposta
				tdg = tdg .. '<br/>' .. mostra2(pid, '* ') .. '<br/>'
				for i, v in pairs(tSx) do
					tdg = tdg .. i .. ' = ' .. v .. ' - '
				end
			end
			n = n + 1
		end
		if  (sposta > 0) then
			pers[pid].x = pers[pid].x + sposta
			pers[pid].sp = pers[pid].sp + sposta
			if (riallinea(pers[pid].padre, frt, fine) == 1) then verifica(pid) end
			sposta = 0
		end
		frt = frt + 1
	end
end

local function calcolaX1(pid)
	local tt = 0
	for i, v in pairs(pers[pid].figli) do
		calcolaX1(v)
		tt = i
	end
	
	if (tt == 0) then -- non ha figli
		if (pers[pid].padre == -1) then -- è capostipite
			pers[pid].x = 0
		elseif (pers[pers[pid].padre].figli[1] == pid) then -- è primo figlio
			pers[pid].x = 0
		else -- è figlio successivo
			pers[pid].x = pers[pers[pers[pid].padre].figli[pers[pid].id2 - 1]].x + 2
		end
	elseif (tt == 1) then -- ha un figlio
		if (pers[pid].padre == -1) then -- è capostipite
			pers[pid].x = pers[pers[pid].figli[1]].x
		elseif (pers[pers[pid].padre].figli[1] == pid) then -- è primo figlio
			pers[pid].x = pers[pers[pid].figli[1]].x
		else -- è figlio successivo
			pers[pid].x = pers[pers[pers[pid].padre].figli[pers[pid].id2 - 1]].x + 2
			pers[pid].sp = pers[pid].x - pers[pers[pid].figli[1]].x
		end
	else -- ha più figli
		local media = math.floor((pers[pers[pid].figli[1]].x + pers[pers[pid].figli[tt]].x)/2)
		if (pers[pid].padre == -1) then -- è capostipite
			pers[pid].x = media
		elseif (pers[pers[pid].padre].figli[1] == pid) then -- è primo figlio
			pers[pid].x = media
		else -- è figlio successivo
			pers[pid].x = pers[pers[pers[pid].padre].figli[pers[pid].id2 - 1]].x + 2
			pers[pid].sp = pers[pid].x - media
		end
	end
	if (tt>0 and pers[pid].padre>-1) then
		if not (pers[pers[pid].padre].figli[1] == pid) then
			verifica(pid)
		end
	end
end

local function calcolaX2(pid)
	local tt = {}
	local sposta = 0

	tt = limSx(pid, 0, tt)
	for i, v in pairs(tt) do
		if (v+sposta<0) then
			sposta = -v
		end
	end
	if (sposta > 0) then
		pers[pid].x = pers[pid].x + sposta
		pers[pid].sp = pers[pid].sp + sposta
	end
end

local function calcolaX3(pid, sposta)
	pers[pid].x = pers[pid].x + sposta
	local sposta2 = sposta + pers[pid].sp
	for i, v in pairs(pers[pid].figli) do
		calcolaX3(v, sposta2)
	end
end

local function massimoXY(pid, x, y)
	local t = {}
	t[1] = math.max(x,pers[pid].x)
	t[2] = math.max(y,pers[pid].y)
	for i, v in pairs(pers[pid].figli) do
		t = massimoXY(v,t[1],t[2])
	end
	return t
end

local function mostra(pid,allinea,largo)
	local xy = massimoXY(pid, 0, 0)
	local p1, p2, p3, n1, n2, n3, s1, s2, s3, px, nx
	local ss = ''
	if (allinea == 'destra') then
		ss = '<div class="floatright" style="width:'..largo..'px;padding:3px;background:#fff;border:1px solid #c8ccd1"><table cellpadding="1" cellspacing="0" border=0 style="text-align:center;line-height:110%;margin:0px auto">'
	else
		ss = '<center><table cellpadding="1" cellspacing="0" border=0 style="text-align:center;font-size:95%;line-height:110%;margin:10px auto">'
	end
	local lg = math.floor(100/(xy[1]+2))
	if (lg == 0) then lg = 1 end
	for n=1,xy[2] do
		p1 = 0; p2 = 0; p3 = 0
		n1 = 0
		if (n==1) then s1 = '<tr>' else s1 = '<tr style="line-height:6px">' end
		s2 = '<tr>'
		if (n<xy[2]) then s3 = '<tr style="line-height:6px">' else s3 = '' end
		for i, v in pairs(tabella[n]) do
			px = pers[v].x
			nx = pers[v].padre

			if (n>1) then
				s1 = s1 .. '<td style="border-right:1px solid #000'
				if (n1 == nx) then s1 = s1 ..';border-top:1px solid #000' end
				n1 = nx
				if (px - p1 > 0) then s1 = s1 .. '" colspan="' .. (px+1-p1)  end
				p1 = px + 1
				s1 = s1 ..	'">&nbsp;</td>'
			else
				for m=1,(xy[1]+2) do s1 = s1 .. '<td width='..lg..'%></td>' end
			end

			if (px-p2>0) then
				s2 = s2 .. '<td'
				if (px - p2>1) then s2 = s2 .. ' colspan="'.. (px-p2) ..'"' end
				s2 = s2 .. '>&nbsp;</td>'
			end
			s2 = s2 .. '<td colspan=2>' .. pers[v].testo .. '<br/>'
			if (pers[v].nota == '-') then else s2 = s2 .. '<span style="font-size:90%"><i>' .. pers[v].nota .. '</i></span>' end
			s2 = s2 .. '</td>'
			p2 = px + 2

			if (n<xy[2]) then
				if (#pers[v].figli > 0) then
					s3 = s3 .. '<td style="border-right: 1px solid #000'
					if (px - p3 > 0) then s3 = s3 .. '" colspan="' .. (px+1-p3) end
					p3 = px + 1
					s3 = s3 ..	'">&nbsp;</td>'
				end
			end
		end
		if (n>1) then s1 = s1 .. '</tr>' end
		s2 = s2 .. '</tr>'
		if (n<xy[2]) then s3 = s3 .. '</tr>' end
		ss = ss .. s1 .. s2 .. s3
		n = n + 1
	end
	ss = ss .. '</table>'
	if (allinea == 'destra') then ss = ss .. '</div>' else ss = ss .. '</center>' end
	return ss
end

function p.main(frame)
	local capo = -1
	local err = 0
	err = dividi(frame.args[1])
	if (err == 0) then
		for i, v in pairs(pers) do
			if (v.padre == -1) then
				capo = v.id
			else
				if (pers[v.padre]) then
					table.insert(pers[v.padre].figli,i)
				else
					err = i
				end
			end
		end

		if (err == 0) then
			if (capo == -1) then
				return '<p style="color:red;font-weight:bold">Template:Discendenza - Non è stato indicato un capostipite</p>[[Categoria:Errori di compilazione del template Discendenza]]'
			else
				organizza(capo, 1)
				calcolaX1(capo)
				calcolaX2(capo)
				calcolaX3(capo, 0)

				if (frame.args[4] == '0') then
					return mostra(capo, frame.args[2], frame.args[3])
				else
					return '<pre>'..mostra2(capo, '')..tdg .. '</pre>'
				end
			end
		else
			return '<p style="color:red;font-weight:bold">Template:Discendenza - Errore nel riferimento al genitore per l\'identificativo ' .. err .. '</p>[[Categoria:Errori di compilazione del template Discendenza]]'
		end
	elseif (err == -1) then
		return '<p style="color:red;font-weight:bold">Template:Discendenza - Errore nel numero di parametri</p>[[Categoria:Errori di compilazione del template Discendenza]]'
	else
		return '<p style="color:red;font-weight:bold">Template:Discendenza - Errore nell\'identificativo o nel riferimento al genitore per l\'elemento ' .. err .. ' in ordine di inserimento</p>[[Categoria:Errori di compilazione del template Discendenza]]'
	end
end

return p