Modul:Grafic de audiență TV

Documentația acestui modul poate fi creată la Modul:Grafic de audiență TV/doc

-- Acest modul implementează {{Grafic de audiență TV}}.

--------------------------------------------------------------------------------
-- Clasa GATV.
-- Clasa principală.
--------------------------------------------------------------------------------

local GATV = {}

-- Conversie coduri hexa în valori RGB.
function GATV.hex2rgb(hex)
    hex = hex:gsub('#', '')
    if #hex == 3 then
    	-- format #000
    	return tonumber("0x"..hex:sub(1,1)..hex:sub(1,1))/256, tonumber("0x"..hex:sub(2,2)..hex:sub(2,2))/256,
    		   tonumber("0x"..hex:sub(3,3)..hex:sub(3,3))/256
	else
    	-- format #000000
    	return tonumber("0x"..hex:sub(1,2))/256, tonumber("0x"..hex:sub(3,4))/256, tonumber("0x"..hex:sub(5,6))/256
    end
end

-- Permite utilizarea de celule {{N/A}}
function GATV.NACell(frame,text)
	local cell = mw.html.create('td')
	local attrMatch = '([%a-]*)="([^"]*)"'
	
	infoParam = frame:expandTemplate{title='N/A',args={text}}
	
	-- Preia stilurile din {{N/A}} și le asociază la variabila nod
	while true do
		local a,b = string.match(infoParam,attrMatch)
		if a == nil or b == nil then break end
		cell:attr(a,b)
		infoParam = string.gsub(infoParam,attrMatch,'',1)
	end

	infoParam = string.gsub(infoParam,'%s*|%s*','',1)
	cell:wikitext(infoParam)
	
	return cell
end

-- Creare grafic și tabel
function GATV.new(frame,args)
	args = args or {}
	
	-- Variabile
	local timeline = ''
	local longestseason = -1
	local average = args.average and 1 or 0
	local season_title = args.season_title or 'Sezon'
	local definite = {Sezon = 'Sezonul', Serie = 'Seria'}
	local root = mw.html.create('div')
		:attr('align', 'center')
	
	-- Creare grafic
	
	-- Număr de cifre de audiență
	local numberargs = 0
	for k,v in pairs(args) do 
		if not string.match(k,'[^%d]+') and not string.match(v,'[^%d%s%.,]+') then numberargs = numberargs + 1 end
	end
	
	-- Lățime bară
	local barwidth
	if numberargs < 20 then barwidth = 8
	elseif numberargs >= 20 and numberargs < 50 then barwidth = 7
	elseif numberargs >= 50 and numberargs < 80 then barwidth = 6
	elseif numberargs >= 80 then barwidth = 5
	end
	
	-- Parametri de bază
	timeline = timeline .. "ImageSize  = width:" .. (args.width or 1000) .. " height:" .. (args.height or 300) .. "\n"
	timeline = timeline .. "PlotArea   = left:50 bottom:70 top:20 right:50\n"
	timeline = timeline .. "AlignBars  = justify\n"
	
	timeline = timeline .. "Colors     =\n"
	timeline = timeline .. " id:a value:gray(0.7)\n"
	
	-- Determinare număr de sezoane
	local num_seasons = -1
	for k,v in pairs(args) do
		local thisseason = tonumber(string.sub(k,6))
		if string.sub(k,1,5) == 'color' and thisseason > num_seasons then
			num_seasons = thisseason
		end
	end
	
	-- Variabile de culoare și legendă
	local season = 1
	for season = 1,num_seasons do 
		local r,g,b = GATV.hex2rgb(args['color' .. season] or '#006600')
		timeline = timeline .. " id:sez" .. season .. " value:rgb("..r..","..g..","..b..") legend:" ..
			string.gsub(string.gsub((args["legend" .. season] or (definite[season_title] or season_title) .. " " .. season), ' ', '_'), "''(.-)''", '%1') .. "\n"
		season = season + 1
	end

	-- Determinare vârf de audiență
	local maxviewers = -1
	local multiple = 'milioane'
	for k,v in pairs(args) do
		local num = tonumber((v:gsub("[%s%.   ]",""):gsub("&nbsp;",""):gsub("&#8199;",""):gsub(",", ".")))
		if tonumber(k) ~= nil and num ~= nil and num > maxviewers then
			maxviewers = num
		end
	end
	if maxviewers <= 1.5 then
		multiple = 'mii'
		maxviewers = maxviewers*1000
		for k, v in pairs(args) do
			local num = tonumber((v:gsub("[%s%.   ]",""):gsub("&nbsp;",""):gsub("&#8199;",""):gsub(",", ".")))
			if tonumber(k) ~= nil and num ~= nil then args[k] = tostring(num*1000) end
		end
	end

	-- Alți parametri; limita superioară este vârful de audiență, aproximat prin adaos
	timeline = timeline .. "DateFormat = x.y\n"
	timeline = timeline .. "Period     = from:0 till:" .. math.ceil(maxviewers) .. "\n"
	timeline = timeline .. "TimeAxis   = orientation:vertical\n"
	timeline = timeline .. "ScaleMajor = gridcolor:a increment:" .. 10^math.ceil(math.log10(maxviewers)-math.log10(15)) .. " start:0\n"
	timeline = timeline .. "Legend     = orientation:horizontal\n"
	
	-- Stabilire parametru de interval pentru a preveni suprapunerea barelor
	local bar = 1
	if args.intervals then
		timeline = timeline .. "BarData    =\n"
		for k,v in pairs(args) do
			if v == '?' then v = '' end
			if tonumber(k) ~= nil and (tonumber((v:gsub("[%s%.   ]",""):gsub("&nbsp;",""):gsub("&#8199;",""):gsub(",", "."))) ~= nil or v == '') and (average == 0 or (average == 1 and args[k+1] ~= '-' and args[k+1] ~= nil)) then
				timeline = timeline .. "  bar:"..bar.."  text:"..((bar == 1 or bar % args.intervals == 0) and bar or '&nbsp;').."\n"
				bar = bar + 1
			end
		end
	end

	-- Date grafic
	timeline = timeline .. "PlotData   =\n"
	timeline = timeline .. "  width:" .. (args.bar_width or barwidth) .. "\n"
	timeline = timeline .. "  mark:(line,black)\n"
	
	-- Adaugă barele la grafic, câte una pentru fiecare cifră de audiență
	local bar = 1
	local season = 0
	local thisseason = 0
	
	for k,v in pairs(args) do
		if v == '?' then v = '' end
		if tonumber(k) ~= nil then
			if v == '-' then
				-- Cratima înseamnă sezon nou, deci schimbă culoarea sezonului
				season = season + 1
				
				-- Determinare număr maxim de episoade per sezon
				if thisseason > longestseason then
					longestseason = thisseason
				end
				thisseason = 0
			elseif average == 0 or (average == 1 and args[k+1] ~= '-' and args[k+1] ~= nil) then
				-- Includere bară neagră ca bordură
				timeline = timeline .. "  color:black\n"
				timeline = timeline .. "  bar:" .. bar .. " width:" .. ((args.bar_width or barwidth)+2) .. " from:start till:" .. (v ~= '' and (v:gsub("[%s%.   ]",""):gsub("&nbsp;",""):gsub("&#8199;",""):gsub(",", ".")) or 'start') .. "\n"
				
				-- Includere bară pentru cifra de audiență, nu se include dacă sunt incluse medii și dacă următorul parametru e un marcator de sezon nou
				timeline = timeline .. "  color:sez" .. season .. "\n"
				timeline = timeline .. "  bar:" .. bar .. " from:start till:" .. (v ~= '' and (v:gsub("[%s%.   ]",""):gsub("&nbsp;",""):gsub("&#8199;",""):gsub(",", ".")) or 'start') .. "\n"
				
				-- Incrementare contoare
				thisseason = thisseason + 1
				bar = bar + 1
			end
		end
	end
	-- Determinare număr maxim de episoade într-un sezon după ultimele bare
	if thisseason > longestseason then
		longestseason = thisseason
	end
	
	-- Etichete axe
	local countryDisplayUS, countryDisplayUK, countryDisplayOther
	if args.country ~= nil and args.country ~= '' then
		if args.country == "U.S." or args.country == "United States" or args.country == "Statele Unite" or args.country == "SUA" then countryDisplayUS = 'SUA'
		elseif args.country == "U.K." or args.country == "United Kingdom" or args.country == "UK" or args.country == "Marea Britanie" or args.country == "Regatul Unit" then countryDisplayUK = 'Regatul Unit'
		elseif args.country == "ro" or args.country == "Ro" or args.country == "RO" or args.country == "Romania" then countryDisplayOther = 'România'
		elseif args.country == "md" or args.country == "MD" or args.country == "RM" or args.country == "Moldova" then countryDisplayOther = 'Republica Moldova'
		else countryDisplayOther = args.country
		end
	end
	timeline = timeline .. "TextData =\n"
	timeline = timeline .. "  pos:(" .. ((args.width or 1000)/2-18) .. ",45) textcolor:black fontsize:S text:Episod\n"
	timeline = timeline .. "  pos:(10," .. ((args.height or 300)-10) .. ") textcolor:black fontsize:S text:" .. "Audiență" .. (((countryDisplayUS or countryDisplayUK or countryDisplayOther) and (" în " .. (countryDisplayUS or countryDisplayUK or countryDisplayOther))) or "") .. " (" .. multiple .. ")\n"
	
	-- Dacă există un titlu, este adăugat la titlul graficului
		if args.title ~= nil and args.title ~= '' then
			root:wikitext("'''''" .. args.title .. "'': Audiență " .. (((countryDisplayUS or countryDisplayUK or countryDisplayOther) and ("în " .. (countryDisplayUS or countryDisplayUK or countryDisplayOther) .. " ")) or "") .. "(" .. multiple .. ")'''")
		else
			root:wikitext("'''Audiență la fiecare episod (" .. multiple .. ")'''")
		end

	-- Adăugare grafic la div
	if args.nograph == nil then
		root:node(frame:extensionTag('timeline', timeline))
	end
	
	-- Creare tabel de audiență
	if args.notable == nil then
		local rtable = mw.html.create('table')
		   	:addClass('wikitable')
			:css('text-align', 'center')
		
		-- Dacă cel mai lung sezon are cel puțin 20 de episoade
		if longestseason >= 20 then
			-- Celule antet pentru episoadele 1 până la maxim
			local row = rtable:tag('tr')
			row:tag('th'):wikitext(season_title)
				:attr('colspan','2')
				:attr('rowspan','2')
				
			row:tag('th')
				:attr('colspan',longestseason)
				:wikitext("Număr de episoade")
				
			-- Coloană medii
			if average == 1 then
				row:tag('th')
				   :attr('scope','col')
				   :attr('rowspan','2')
				   :wikitext("''Medie''")
			end
			
			local row = rtable:tag('tr')
			
			for i = 1,longestseason do
				row:tag('th')
				   :attr('scope','col')
				   :wikitext(i)
			end
		else
			-- Celule antet pentru episoadele 1 până la maxim
			local row = rtable:tag('tr')
			row:tag('th'):wikitext(season_title)
				:attr('colspan','2')
			
			for i = 1,longestseason do
				row:tag('th')
				   :attr('scope','col')
				   :wikitext(frame:expandTemplate{ title='Abr', args={ 'Ep.', 'Episodul' } } .. ' ' .. i)
			end
			
			-- Coloană medii
			if average == 1 then
				row:tag('th')
				   :attr('scope','col')
				   :wikitext("''Medie''")
			end
		end
		
		local season = 1
		local thisseason = 0
		
		-- Creare rânduri și coloane în tabel
		for k,v in pairs(args) do
			if tonumber(k) ~= nil then
				-- Marcator de sezon nou sau audiență pentru episod final
				if v == '-'  or (average == 1 and args[k+1] == nil) then
					if season > 1 then
						-- Umplere celule goale cu {{N/A}}
						if thisseason < longestseason then
							row:node(GATV.NACell(frame,"—"):attr('colspan',longestseason-thisseason))
						end
						
						if average == 1 then
							-- Dacă sunt incluse medii, setează celulele cu valori sau cu „—”
							if v ~= '' then
								row:tag('td'):attr('style','white-space:nowrap'):wikitext(args[k+1] ~= nil and args[k-1] or v)
							else
								row:node(GATV.NACell(frame,"—"))
							end
							thisseason = thisseason + 1
						end
					end
					
					-- Marcator de sezon nou
					if v == '-' then
						-- Rând nou
						row = rtable:tag('tr')
						row:tag('th')
							:css('background-color', args['color' .. season])
							:css('width','10px')
						
						row:tag('th')
						   :attr('scope','row')
						   :wikitext(args["legend" .. season] and args["legend" .. season] or season)
						
						thisseason = 0
						season = season + 1
					end
				elseif average == 0 or (average == 1 and args[k+1] ~= '-' and args[k+1] ~= nil) then
					-- Cifre de audiență, ca număr sau ca „—”
					if v == '?' then
						row:node(GATV.NACell(frame,"—"))
					elseif v ~= '' then
						row:tag('td'):attr('style','white-space:nowrap'):wikitext(v)
					else
						row:node(GATV.NACell(frame,"—"))
					end
					thisseason = thisseason + 1
				end
			end
		end
		
		-- Finisare prin verificarea dacă ultimul rând are nevoie de celule {{N/A}}
		if average == 0 and thisseason < longestseason then
			row:node(GATV.NACell(frame,"—"):attr('colspan',longestseason-thisseason))
		end
			
		-- Adăugare tablel la rădăcina divului; revenire
		root:node(rtable)
	end
	
	local span = mw.html.create( 'span' )
		span:css( 'color', 'red' )
		    :wikitext(frame:expandTemplate{ title='fix', args={ txt = "<span color='red'>'''referință?'''</span>" } })
	     
	if countryDisplayUS then
		root:wikitext("<small>Sursa: [[Indicii Nielsen|Nielsen Media Research]]</small>" .. (args.refs or tostring(span)))
	else
		root:wikitext("<small>Sursa: </small>" .. (args.refs or tostring(span)))
	end
	
	return tostring(root)
end

--------------------------------------------------------------------------------
-- Export
--------------------------------------------------------------------------------

local p = {}

function p.main(frame)
	local origArgs = require('Modul:Arguments').getArgs(frame, {
		removeBlanks = false,
		wrappers = 'Format:Grafic de audiență TV'
	})
	local args = {}
	
	-- Traducere parametri din română în engleză
	for k,v in pairs(origArgs) do
		if k == 'titlu' then args['title'] = v
		elseif k == 'titlu_sezoane' then args['season_title'] = v
		elseif k == 'fără_grafic' then args['nograph'] = v
		elseif k == 'fără_tabel' then args['notable'] = v
		elseif string.sub(k,1,7) == 'culoare' then args[ 'color' .. string.sub(k,8,-1) ] = v
		elseif string.sub(k,1,7) == 'legendă' then args[ 'legend' .. string.sub(k,8,-1) ] = v
		elseif k == 'ref' then args['refs'] = v
		elseif k == 'lățime' then args['width'] = v
		elseif k == 'înălțime' then args['height'] = v
		elseif k == 'medii' then args['average'] = v
		elseif k == 'medie' then args['average'] = v
		elseif k == 'intervale' then args['intervals'] = v
		elseif k == 'lățime_bară' then args['bar_width'] = v
		elseif k == 'țară' then args['country'] = v
		elseif args[k]==nil or args[k]=='' then args[k] = v
		end
	end
	
	origArgs = nil
	
	return GATV.new(frame,args)
end

return p