Documentation for this module may be created at Module:Sandbox/Premeditated/WDTracklist/doc

local hlist = require('Module:List')
local exception = mw.loadData('Module:Sandbox/Premeditated/WDTracklist/exception')

local p = {}
local allCredits = {}

local function parseDate(totalSeconds)
	local seconds =  math.fmod(tonumber(totalSeconds),60)
	local minutes =  math.floor(tonumber(totalSeconds) / 60)
	local hours   = math.floor(minutes / 60)
	return string.format("%d:%02d", minutes, seconds)
end

local function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end

local function getOrder(qualifiers)
	local out = nil
	if qualifiers then
		local qualifierID = "P1545" -- sorting order / rank / series ordinal
		if qualifiers[qualifierID] then
			for k, v in pairs(qualifiers[qualifierID]) do
				if v.snaktype == 'value' then
					out = v.datavalue.value
				end
			end
		end
	end
	return out
end

local function has_value (tab, val)
    for index, value in ipairs(tab) do
        if value == val then
            return true
        end
    end

    return false
end

local function getWDName(id, pid)
	local num = 0
	local name = {}
	
	if id["claims"][pid] and not id["claims"][pid][2] then
		local famNameItem = mw.wikibase.getEntity(id["claims"][pid][1]["mainsnak"]["datavalue"]["value"]['id'])
		table.insert(name, famNameItem:getLabel())
		return name
	end
	
	for index, claims in pairs(id["claims"][pid]) do
		local famNameItem = mw.wikibase.getEntity(claims["mainsnak"]["datavalue"]["value"]['id'])
		if claims.qualifiers then
			name[tonumber(getOrder(claims.qualifiers))] = famNameItem:getLabel()
		else
			table.insert(name, famNameItem:getLabel())
		end
	end
	if name then
		return name
	end
	
	return ''
end

local function getName(id)
	
	if id["claims"] and id["claims"]["P1477"] and id["claims"]["P1477"][1] then
		for index, claims in pairs(id["claims"]["P1477"]) do
			if claims["mainsnak"]["datavalue"]["value"]["language"] == 'en' then 
				return claims["mainsnak"]["datavalue"]["value"]["text"]
			end
		end
		return id["claims"]["P1477"][1]["mainsnak"]["datavalue"]["value"]["text"]
	end
	
	if id["claims"] and id["claims"]["P734"] and id["claims"]["P734"][1] and id["claims"]["P735"] and id["claims"]["P735"][1] then
		local fullName = TableConcat(getWDName(id, 'P735'), getWDName(id, 'P734'))
		return table.concat(fullName, " ")
	end
	
	return id:getLabel()
end

local function getFamilyName(label)
	local words = {}
	local suffix = {'jr', 'sr', 'jr.', 'sr.'}
	for word in label:gmatch("[%w\128-\244]+") do table.insert(words, word) end
	if has_value(suffix, words[#words]:lower()) then
		return words[#words - 1] .. ' ' .. words[#words] .. '.'
	end
	return words[#words]
end

local function findLast(haystack, needle)
    local i = haystack:match(".*"..needle.."()")
    if i == nil then return nil else return i-1 end
end

local function replace_char(pos, str, r)
    return str:sub(1, pos-1) .. r .. str:sub(pos+1)
end

local function getFeature(performer, frame)
	local feat = {}
	
	for index22, table22 in pairs(performer) do
    	if table22["qualifiers"] and table22["qualifiers"]["P3831"] and table22["qualifiers"]["P3831"][1]["datavalue"]["value"]["id"] then
    		for index23, table23 in pairs(table22["qualifiers"]["P3831"]) do
        		if table23["datavalue"]["value"]["id"] == 'Q1399352' then
        			local featureArtist = mw.wikibase.getEntity(table22["mainsnak"]["datavalue"]["value"]["id"])
        			if featureArtist:getSitelink() ~= nil then
        				table.insert(feat, frame:preprocess("[[" .. featureArtist:getSitelink() .. "|" .. featureArtist:getLabel() .. "]]"))
        			else
        				table.insert(feat, frame:preprocess(featureArtist:getLabel()))
        			end
        			break
        		end
    		end
    	end
	end
	
	if next(feat) ~= nil then
		local text = "featuring " .. table.concat(feat,", ")
		local last = findLast(text,"%,")
		if last == nil then return text else return replace_char(last, text, ' and') end
	end
	
	return ''
end

local function getCredits(frame, credits)
	local credit = {}
	

	for index, we in pairs(credits) do
		if not we["mainsnak"]["datavalue"] then
			return ''
		end
		
    	local id = mw.wikibase.getEntity(we["mainsnak"]["datavalue"]["value"]["id"])
    	
    	if has_value(allCredits, id:getLabel()) then
    		local name = getName(id)
    		if has_value(exception['name_exception_qid'], id:getId()) or has_value(exception['name_exception'], id:getLabel()) then
    			table.insert(credit, id:getLabel())
    		else
    			table.insert(credit, getFamilyName(name))
    		end
    	else
    		if id:getSitelink() ~= nil then
    			table.insert(credit, frame:preprocess( "[[" .. id:getSitelink() .. "|" .. getName(id) .. "]]"))
    		else
    			table.insert(credit, getName(id))
    		end
    		table.insert(allCredits, id:getLabel())
    	end
    end
	
	return hlist.makeList('horizontal', credit)
end

function p.parseNames(frame)
	
	if mw.wikibase.getEntity() == nil and frame.args[1] == '' then
		return ''
	end
	
	local wikiEntity = mw.wikibase.getEntity(frame.args[1]) or mw.wikibase.getEntity()
		
	if wikiEntity == nil or wikiEntity == '' then
		return ''
	end
	
	local funcArgs = {}
	
	for index, table in pairs(wikiEntity:getAllStatements( 'tracklist' )) do
		local trackEntity = mw.wikibase.getEntity( table["mainsnak"]["datavalue"]["value"]["id"] )
		
		local order = tonumber(getOrder(table.qualifiers)) or index
			
		if trackEntity:getSitelink() == nil then
			local success = false
			if trackEntity["claims"]["P2550"] ~= nil then
				for index, recOrPerf in pairs(trackEntity:getAllStatements( 'P2550' )) do
					local trackEntityRec = mw.wikibase.getEntity( recOrPerf["mainsnak"]["datavalue"]["value"]["id"] )
					if trackEntityRec:getSitelink() ~= nil then
						funcArgs["title" .. order] = frame:preprocess( "[[" .. trackEntityRec:getSitelink() .. "|" .. trackEntity:getLabel() .. "]]")
						success = true
						break
					end
				end
			end
			if success == false then
				funcArgs["title" .. order] = trackEntity:getLabel()
			end
		else
			funcArgs["title" .. order] = frame:preprocess( "[[" .. trackEntity:getSitelink() .. "|" .. trackEntity:getLabel() .. "]]")
		end
		
		if trackEntity["claims"]["P2047"] ~= nil then
			funcArgs["length" .. order] = parseDate(tonumber(trackEntity["claims"]["P2047"][1]["mainsnak"]["datavalue"]["value"]["amount"]))
		end
		
		if trackEntity["claims"]["P676"] ~= nil then
			funcArgs["writer" .. order] = getCredits(frame, trackEntity["claims"]["P676"])
		end
		
		if trackEntity["claims"]["P175"] ~= nil then
			funcArgs["note" .. order] =  getFeature(trackEntity:getAllStatements( 'performer' ), frame)
		end
		
		if trackEntity["claims"]["P162"] ~= nil then
			funcArgs["extra_column"] = 'Producer(s)'
			funcArgs["extra" .. order] = getCredits(frame, trackEntity["claims"]["P162"])
		end
		
		if table["qualifiers"] ~= nil then
			if table["qualifiers"]["P2047"] ~= nil then
				local timeInSeconds = table["qualifiers"]["P2047"][1]["datavalue"]["value"]["amount"]
				funcArgs["length" .. order] = parseDate(timeInSeconds)
			end
		end
	end
	if wikiEntity['claims']['P2047'] ~= nil then
		local totalTime = tonumber(wikiEntity:getAllStatements( 'duration' )[1]["mainsnak"]["datavalue"]["value"]["amount"])
		funcArgs["total_length"] = parseDate(totalTime)
	end
	return frame:expandTemplate{ title = 'tracklist', args = funcArgs }
	
end

return p