모듈:Lineage

require('strict')
local getArgs = require('Module:Arguments').getArgs
local errorCategory = 'Categoria:Errors reported by Module Lineage'
local mwHtml = getmetatable( mw.html.create() ).__index
function mwHtml:attrIf( cond, name, value )
if cond then
return self:attr( name, value )
else
return self
end
end
function mwHtml:cssIf( cond, name, value )
if cond then
return self:css( name, value )
else
return self
end
end
function mwHtml:wikitextIf( cond, value1, value2 )
if cond then
return self:wikitext( value1 )
elseif value2 ~= nil then
return self:wikitext( value2 )
else
	return self
end
end
local p = {}
local pers = {}
local tabella = {}
local function errhandler(msg)
	local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or 
	return string.format('%s%s', msg, cat)
end
local function dividi(dati)
	local n = 1
	local resto = 0
	local nx,px
	while (datin) do n = n + 1 end
	n = n-1
	for m = 4, n, 4 do
		nx = tonumber(datim-3)
		px = tonumber(datim-2)
		if nx then
			if px then
				if persnx then
					error(string.format('Duplicated id %d',nx))
				else
					persnx = { padre = px, testo = datim-1, nota = datim, id = -1, x = -1, y = -1, sp = 0, figli = {} }
				end
			else
				error(string.format('Erroneous parent id %s for id %d',datim-2,nx))
			end
		else
			error(string.format('Erroneous id %s',datim-3))
		end
		resto = n-m
	end
	if resto > 0 then
		error(string.format('Erroneous number of data %d (elementi in più: %d)',n))
	end
end
local function organizza(pid, y)
	local nn = 1
	perspid.y = y
	if (not tabellay) then tabellay = {} end
	table.insert(tabellay, pid)
	for i, v in pairs(perspid.figli) do
		persv.id = i
		nn = nn + organizza(v, y+1)
	end
	return nn
end
local function limSx(pid, delta, dt)
	if (dtperspid.y) then
		dtperspid.y = math.min(dtperspid.y, perspid.x+delta)
	else
		dtperspid.y = perspid.x + delta
	end
	for _, v in pairs(perspid.figli) do
		dt = limSx(v, delta+perspid.sp, dt)
	end
	return dt
end
local function limDx(pid, delta, dt)
	if (dtperspid.y) then
		dtperspid.y = math.max(dtperspid.y, perspid.x+delta)
	else
		dtperspid.y = perspid.x + delta
	end
	for _, v in pairs(perspid.figli) do
		dt = limDx(v, delta+perspid.sp, dt)
	end
	return dt
end
local function riallinea(pid2, n1, n2)
	local distanza = n2 - n1
	local vrf = 0
	local pos, inizio, passo
	if (distanza > 1) then
		inizio = persperspid2.figlin1.x
		passo = (persperspid2.figlin2.x - inizio)/distanza
		for cc=1, (distanza-1) do
			pos = inizio + math.floor(cc*passo)
			if (pos - persperspid2.figlin1+cc.x > 0) then
				persperspid2.figlin1+cc.x = pos
				persperspid2.figlin1+cc.sp = pos
			end
		end
		vrf = 1
	end
	return vrf
end
local function verifica(pid)
	local tSx
	local tDx
	local sposta = 0
	local fine = perspid.id
	local frt2, n
	
	for frt=1, (fine-1) do
		frt2 = persperspid.padre.figlifrt
		tDx = limDx(frt2, 0, {})
		tSx = limSx(pid, 0, {})
		n = perspid.y
		while tSxn and tDxn do
			if (tSxn - tDxn + sposta  0) then
			perspid.x = perspid.x + sposta
			perspid.sp = perspid.sp + sposta
			if (riallinea(perspid.padre, frt, fine) == 1) then verifica(pid) end
			sposta = 0
		end
	end
end
local function calcolaX1(pid)
	for _, v in pairs(perspid.figli) do
		calcolaX1(v)
	end
	local tt = #perspid.figli
	if (tt == 0) then
		if (perspid.padre == -1 or perspid.id == 1) then
			perspid.x = 0
		else
			perspid.x = perspersperspid.padre.figliperspid.id - 1.x + 2
		end
	elseif (tt == 1) then
		if (perspid.padre == -1 or perspid.id == 1) then
			perspid.x = persperspid.figli1.x
		else
			perspid.x = perspersperspid.padre.figliperspid.id - 1.x + 2
			perspid.sp = perspid.x - persperspid.figli1.x
			verifica(pid)
		end
	else
		local media = math.floor((persperspid.figli1.x + persperspid.figlitt.x)/2)
		if (perspid.padre == -1 or perspid.id == 1) then
			perspid.x = media
		else
			perspid.x = perspersperspid.padre.figliperspid.id - 1.x + 2
			perspid.sp = perspid.x - media
			verifica(pid)
		end
	end
end
local function calcolaX2(pid)
	local sposta = 0
	local tt = limSx(pid, 0, {})
	for _, v in pairs(tt) do
		if (v+sposta 0) then
		perspid.x = perspid.x + sposta
		perspid.sp = perspid.sp + sposta
	end
end
local function calcolaX3(pid, sposta)
	perspid.x = perspid.x + sposta
	for _, v in pairs(perspid.figli) do
		calcolaX3(v, sposta + perspid.sp)
	end
end
local function massimoXY(pid, t)
	if (perspid.x > t1) then t1 = perspid.x end
	if (perspid.y > t2) then t2 = perspid.y end
	for _, v in pairs(perspid.figli) do
		t = massimoXY(v,t)
	end
	return t
end
local function mostraX(pid,allinea,largo,dida)
	local posx = {}
	local n1
	local stx
	local riga = {}
	local xx, xp
	local stileDiv = { 'width' = largo..'px', 'padding' = '3px', 'background' = '#FFF', 'border' = '1px solid #C8CCD1' }
	local stileTabella = { 'border-collapse' = 'separate', 'text-align' = 'center', 'font-size' = '95%', 'line-height' = '105%', 'margin' = '10px auto !important', }
	local xy = massimoXY(pid, {0, 0})
	local lg = math.floor(100/(xy1+2))
	if (lg == 0) then lg = 1 end
	local bDiv = mw.html.create('div')
	if (allinea == 'right') then
		bDiv:css(stileDiv):addClass('floatright')
		stileTabella'margin' = '0px auto !important'
	end
	local bTabella = mw.html.create('table')
		:css(stileTabella)
		:attr({'cellpadding'='1','cellspacing'='0','border'='0'})
	for n=1,xy2 do
		local riga1 = mw.html.create('tr')
		local riga2 = mw.html.create('tr')
		local riga3 = mw.html.create('tr')
		posx1 = 0; posx2 = 0; posx3 = 0
		n1 = 0
		if (n > 1) then riga1:css('line-height','8px') end
		if (n 0,'colspan',xx+1-posx1)
					:wikitext(' ')
				)
				n1 = xp
				posx1 = xx + 1
			end
			if xx-posx2 > 0 then
				riga2:node(mw.html.create('td')
					:attrIf(xx-posx2>1,'colspan',xx-posx2)
					:wikitext(' ')
				)
			end
			riga2:node(mw.html.create('td')
				:attr('colspan','2')
				:wikitextIf(persv.nota=='-', persv.testo, string.format('%s%s',persv.testo,persv.nota))
			)
			posx2 = xx + 2
			if n  0 then
				riga3:node(mw.html.create('td')
					:css('border-right','1px solid #000')
					:attrIf(xx-posx3>0,'colspan',xx+1-posx3)
					:wikitext(' ')
					)
				posx3 = xx + 1
			end
		end
		bTabella:node(riga1):node(riga2):node(riga3)
	end
	bDiv:node(bTabella)
	if (allinea == 'right' and dida ~= ) then
		bDiv:node(mw.html.create('p')
			:css({'font-size' = '87%', 'font-style' = 'normal', 'border-top' = '1px solid #c8ccd1', 'margin' = '8px 2px 3px'})
			:wikitext(dida)
		)
	end
	return tostring(bDiv)
end
local function calcolaY(pid, t)
	if (perspid.y > t) then t = perspid.y end
	for _, v in pairs(perspid.figli) do
		t = calcolaY(v,t)
		perspid.sp = perspid.sp + 1 + persv.sp
	end
	return t
end
local function mostraY(pid)
	local bTabella = mw.html.create('table')
		:attr({'cellpadding'='0','cellspacing'='0','border'='0'})
		:css({'border-collapse'='separate','text-align'='left','margin'='10px 0 10px 16px'})
local function mostraY2(pid, a)
	if (perspid.padre > -1) then
		local riga1 = mw.html.create('tr')
		local riga2 = mw.html.create('tr')
		local spd = persperspid.padre.sp
		if (perspid.id == 1 and persperspid.padre.padre > -1) then
			riga1:node(mw.html.create('td')
				:attr('rowspan',2*spd))
			riga1:node(mw.html.create('td')
				:attr('rowspan',2*spd)
				:cssIf(persperspid.padre.id  0) then
		for _, v in pairs(perspid.figli) do
			mostraY2(v,a-1)
		end
	end
end
	mostraY2(pid,calcolaY(pid,0))
	return tostring(bTabella)
end
function p._lineage(args)
	local capo = -1
	local n1, n2
	local lato = args'align' or 'center'
	local larg = args'width' or '300'
	local tipo = args'show' or 'h'
	local dida = args'caption' or 
	dividi(args)
	n1 = 0
	for i, v in pairs(pers) do
		n1 = n1+1
		if (v.padre == -1) then
			if (capo == -1) then
				capo = i
			else
				error(string.format('Duplicated progenitor (id = %d, %d)',capo,i))
			end
		else
			if (v.padre == i) then
				error(string.format('%d is parent of himself', i))
			elseif (persv.padre) then
				table.insert(persv.padre.figli,i)
			else
				error(string.format('Erroneous parent id %d for row with id %d',v.padre,i))
			end
		end
	end
	if (capo == -1) then
		error('Progenitor not found')
	else
		n2 = organizza(capo, 1)
		if (n1 == n2) then
			if (tipo == 'v') then
				return mostraY(capo)
			elseif (tipo == 'h') then
				calcolaX1(capo)
				calcolaX2(capo)
				calcolaX3(capo, 0)
				return mostraX(capo, lato, larg, dida)
			end
		else
			error('Some elements are not linked to the progenitor')
		end
	end
end
function p.lineage(frame)
	local args = getArgs(frame, {
		valueFunc = function (key, value)
			if type(key) == "number" then
				if value == nil then
					return nil
				else
					value = mw.text.trim(value)
				end
			else
				if value ==  then return nil end
end
			return value
		end
	})
	return p._lineage(args)
end
return p