Module:Character

From Granblue Fantasy Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Character/doc

local p = {}
local getArgs = require('Module:Arguments').getArgs

local util = require('Module:Util')

function p.tablecontains(tab, val) 
	for index, value in ipairs(tab) do
		if value == val then
			return true
		end
	end
	return false
end

function p.renderList(frame)
	mw.log('Module:Character: render start: ' .. os.clock())
	local filter = {}
	local titles = {}
	local title_links = {}
	for ix,fil in pairs({'id','titles','title_links','name','link','rarity','element','type','race','gender','charid','obtain','a_tags'}) do
		if frame.args[fil] and (string.len(frame.args[fil]) > 0) then
			if (fil == 'id') and (string.find(frame.args[fil], ';', 1, true) ~= nil) then
				--local character_index = mw.loadData('Module:CharacterList')
				filter[fil] = '(' .. table.concat(mw.text.split(frame.args[fil], ';'), '|') .. ')'
			elseif fil == 'charid' then
				filter[fil] = '[0-9;]*(' .. table.concat(mw.text.split(frame.args[fil], ';'), '|') .. ')'
			elseif fil == 'titles' then
				local temp_titles = mw.text.split(frame.args[fil], ';')
				for title_ix,title_name in pairs(temp_titles) do
					if #title_name > 0 then
						table.insert(titles, mw.text.trim(title_name))
					end
				end
				temp_titles = table.concat(titles, '|')
				temp_titles = string.gsub(temp_titles, '[\(]', '\\(')
				temp_titles = string.gsub(temp_titles, '[\)]', '\\)')
				filter[fil] = temp_titles
				filter['titles_table'] = titles
			elseif fil == 'title_links' then
				local temp_links = mw.text.split(frame.args[fil], ';')
				for title_ix, title_link in pairs(temp_links) do 
				  local temp_title_link = mw.text.split(title_link, '=')
				  title_links[temp_title_link[1]] = temp_title_link[2]
				end
			else
				filter[fil] = frame.args[fil]
			end
		end
	end

	local fields = {
		'%PAGE%',
		'id'
	}
	if frame.args.fields ~= nil then
		for w in (frame.args.fields):gmatch('[^,]+') do
			table.insert(fields, w)
		end
	end

	mw.log('Module:Character: load data: ' .. os.clock())
	local characters = p.fetchCharacters(frame, filter, fields)
		
	mw.log('Module:Character: expanding templates: ' .. os.clock())
	local result = {}
	local template = frame.args.template
	for key,character in pairs(characters) do
		for ix,arg in pairs(frame.args) do
			if character[ix] == nil then
				character[ix] = arg
			end
		end
		
		-- include some params from call
		if frame.args.format ~= nil then
			character.args_format = frame.args.format
		end
		if (frame.args.size ~= nil) then
			character.args_size = frame.args.size
		end
		--mw.logObject(title_links)
		for title_ix, title_custom_link in pairs(title_links) do
			--mw.log('title comparing ' .. title_ix .. ' with ' .. character.link)
			if (title_ix == character.link) then
		 		--mw.log('title found ' .. title_custom_link)
				character.custom_link = title_custom_link
			end
		end

		if frame.args.additionalArgs ~= nil then
			mw.log('Module:Character: passing additional args: ' .. os.clock())
			for arg in (frame.args.additionalArgs):gmatch('[^;]+') do
				local i = arg:find('=')
				character[arg:sub(0, i-1)] = arg:sub(i+1)
			end
		end
		
		table.insert(result, frame:expandTemplate{title = template, args = character})
		--table.insert(result, '')
	end
	mw.log('Module:Character: render end: ' .. os.clock())
	return table.concat(result, '')
end

function p.getCharacterId(frame)
	local args = getArgs(frame)	
	return p._getCharacterId(args)
end

function p.getCharacterField(frame)
	local args = getArgs(frame)	
	return p._getCharacterField(args)
end

function p._getCharacterId(args)
	local queryFields = 'id,_pageName=link,name'
	local queryArgs = { limit = 10, where = '_pageName=\''..util.cargo.escape_sqli(args['name'])..'\'' }
	for _, row in ipairs(mw.ext.cargo.query('characters', queryFields, queryArgs)) do
		return row['id']
	end
end

function p._getCharacterField(args)
	local queryFields = 'id,_pageName=link,'..args['field']..' =custom_field'
	local queryArgs = { limit = 10, where = 'id='..args['id'] }
	for _, row in ipairs(mw.ext.cargo.query('characters', queryFields, queryArgs)) do
		return row['custom_field']
	end
end

function p._getCharacterLinkById(args)
	local character_index = mw.loadData('Module:CharacterList')
	
	local id = tonumber(args['id'])
	if id == nil then
		return ''
	elseif character_index[id] ~= nil then
		return character_index[id]
	end

	local queryFields = 'id,_pageName=link,name'
	local queryArgs = { limit = 10, where = 'id='..id }
	for _, row in ipairs(mw.ext.cargo.query('characters', queryFields, queryArgs)) do
		return row['link']
	end

	return ''
end

function p.getOutfitLinkById(frame)
	local args = getArgs(frame)	
	return p._getOutfitLinkById(args)
end

function p._getOutfitLinkById(args)
	local queryFields = 'outfit_id,outfit_name,char_id,character_id,character_name'
	local queryArgs = { limit = 10, where = 'outfit_id='..args['id'] }
	for _, row in ipairs(mw.ext.cargo.query('character_outfits', queryFields, queryArgs)) do
		if (args['full'] ~= nil) and (args['full'] == 'yes') then
			return string.format('[[%s#%s|%s\'s %s]]',
				row['character_name'], 
				row['outfit_name'],
				row['character_name'], 
				row['outfit_name']
			)
		else
			return string.format('%s#%s', row['character_name'], row['outfit_name'])
		end
	end
end

function p.fetchPageById(frame)
	local character_index = mw.loadData('Module:CharacterList')

	local fields = {
		'%PAGE%',
		'id'
	}

	local id = tonumber(frame.args.id)
	if (id == nil) then
		return ''
	elseif character_index[id] ~= nil then
		return character_index[id]
	end

	local queryFields = 'id,_pageName=link,name'
	local queryArgs = { limit = 10, where = 'id='..id }
	for _, row in ipairs(mw.ext.cargo.query('characters', queryFields, queryArgs)) do
		return row['link']
	end

	return ''
end

function p.fetchCharacters(frame, filter, fields)
	mw.log('Module:Character: fetchCharacters start: ' .. os.clock())
	local argList = fields
	local params = {
		category = 'Characters',
		include = '{Character}:' .. table.concat(argList, ':'),
		mode = 'userformat',
		secseparators = '====',
		multisecseparators = '====',
		notnamespace = 'User',
		skipthispage = 'no',
	}
	if (filter ~= nil) then
		if filter.titles ~= nil then
			params.titleregexp = '^'..filter.titles..'$'
		elseif filter.link ~= nil then
			params.title = filter.link
			params.ordermethod = title
		else
			local match = {}
			for key,part in pairs(filter) do
				table.insert(match, key..'\\s*=\\s*'..part)
			end
			if #match > 0 then
				params.includematch = '/^(?=.*\\b' .. table.concat(match, '\\b)(?=.*\\b') .. '\\b).*$/is'
			end
		end
	end
	mw.log('Module:Character: fetchCharacters dpl start: ' .. os.clock())
	local data = frame:callParserFunction('#dpl:', params)
	mw.log('Module:Character: fetchCharacters dpl end: ' .. os.clock())
	argList[1] = 'link'
	local result = p.indexDPLTable(frame, argList, data)
	if (filter ~= nil) and (filter.titles ~= nil) then
		local temp = {}
		for index,value in pairs(result) do
			if p.tablecontains(filter.titles_table, value.link) then
				table.insert(temp, value)
			end
		end
		return temp
	else
		return result
	end
end

function p.indexDPLTable(frame, argList, data)
	mw.log('Module:Character: indexDPLTable start: ' .. os.clock())
	local result = {}
	local ix = 0
	local rows = util.string.split(data, '====')
	for rowix,row in pairs(rows) do
		local args = {}
		local i = 0
		local sargs = util.string.split(row, '\n|')
		for argix,arg in pairs(sargs) do
			i = i+1
			if arg ~= '' then
				local key = argList[i]
				args[key] = arg
			end
		end
		if args.link ~= nil then
			ix = ix + 1
			args.ix = ix
			
			-- some housework
			if args.race == nil then
				args.race = 'none'
			end
			if args.link == nil then
				args.link = args.name
			end
			if (args.id ~= nil) then
				args.short_id = string.sub(args.id, 3, 3) .. string.sub(args.id, 5, 7)
			else
				args.short_id = nil
			end
			table.insert(result, args)
		end
	end

	if (frame.args.sortby ~= nil) then
		if (frame.args.sortby == 'journal') then
			table.sort(result, function(a,b) 
				if (a.charid == nil) then
					return false
				elseif (b.charid == nil) then
					return true
				elseif (a.charid == b.charid) then
					return a.id < b.id
				else
					return a.charid < b.charid
				end
			end)
		else
			table.sort(result, function(a,b) 
				return a.link < b.link
			end)
		end
	else
		table.sort(result, function(a,b) 
			return a.link < b.link
		end)
	end

	mw.log('Module:Character: indexDPLTable ned: ' .. os.clock())
	return result
end

function p.test()
	mw.log(os.clock())
	local frame = mw.getCurrentFrame()
	mw.log(os.clock())
	local items = p.fetchCharacters(frame, nil, { '%PAGE%','id','charid','name','va','rarity','type','element','race','weapon','release_date','gender','obtain','a_tags','join','min_atk','min_hp','max_atk','max_hp','flb_atk','flb_hp','bonus_atk','bonus_hp','base_evo','max_evo','perk11'})
	mw.log(os.clock())
	local count = 0
    for k,v in pairs(items) do 
    	--mw.log(v.id .. ' ' .. v.short_id .. ' ' .. v.link)
    	count = count + 1 
    end
	mw.log(os.clock())
    return count
end

function p.test2()
	mw.log(os.clock())
	local frame = mw.getCurrentFrame()
	mw.log(os.clock())
	local characters = p.fetchCharacters(frame, nil, { '%PAGE%','id','charid','name','va','rarity','type','element','race','weapon','release_date','gender','obtain','a_tags','join','min_atk','min_hp','max_atk','max_hp','flb_atk','flb_hp','bonus_atk','bonus_hp','base_evo','max_evo','perk11'})
	mw.log(os.clock())
	local result = {}
	for key,character in pairs(characters) do
		mw.log(os.clock())
		table.insert(result, frame:expandTemplate{title = 'SimpleCharacterList/Row', args = character})
		--table.insert(result, '')
	end
	mw.log(os.clock())
	result = table.concat(result, '')
	mw.log(os.clock())
	return result
end

function p.test3()
	local titles = {}
	local temp_titles = mw.text.split('Baotorda;Chloe (Summer);Ippatsu (Summer);Jessica;La Coiffe;Lunalu (Summer);Randall', ';')
	for title_ix,title_name in pairs(temp_titles) do
		if #title_name > 0 then
			table.insert(titles, mw.text.trim(title_name))
		end
	end
	temp_titles = table.concat(titles, '|')
	temp_titles = string.gsub(temp_titles, '[\(]', '\\(')
	temp_titles = string.gsub(temp_titles, '[\)]', '\\)')
	return temp_titles
end

function p.test4()
	mw.log(os.clock())
	local frame = mw.getCurrentFrame()
	mw.log(os.clock())
	local items = p.fetchCharacters(frame, { 
		titles = p.test3(),  
		titles_table = {'Baotorda','Chloe (Summer)','Ippatsu (Summer)','Jessica','La Coiffe','Lunalu (Summer)','Randall'} 
		}, { '%PAGE%','id','name' })
	mw.log(os.clock())
	local count = 0
    for k,v in pairs(items) do 
    	mw.logObject(v)
    	--mw.log(v.id .. ' ' .. v.link)
    	count = count + 1 
    end
	mw.log(os.clock())
    return count
end

function p.test5()
	mw.log(os.clock())
	local frame = mw.getCurrentFrame()
	mw.log(os.clock())
	local items = p.fetchCharacters(frame, { 
		id = '(3020008000|3030095000|3020021000|3040030000|3040103000|3030071000|3040076000|3030179000)',
		}, { '%PAGE%','id','name' })
	mw.log(os.clock())
	local count = 0
    for k,v in pairs(items) do 
    	mw.logObject(v)
    	--mw.log(v.id .. ' ' .. v.link)
    	count = count + 1 
    end
	mw.log(os.clock())
    return count
end

function p.test6()
	mw.log(os.clock())
	local frame = mw.getCurrentFrame()
	mw.log(os.clock())
	local items = p.fetchCharacters(frame, { 
		charid = '[0-9;]*(2050)',
		}, { '%PAGE%','id','name' })
	mw.log(os.clock())
	local count = 0
    for k,v in pairs(items) do 
    	mw.logObject(v)
    	--mw.log(v.id .. ' ' .. v.link)
    	count = count + 1 
    end
	mw.log(os.clock())
    return count
end

function p.test7()
	mw.log('start', os.clock())
	local testString = 'alt=true;arg2=doot;param=arg;foo=bar'
	for arg in (testString):gmatch('[^;]+') do
		local i = arg:find('=')
		mw.log(arg:sub(0, i-1), '===', arg:sub(i+1))
	end
	mw.log('end', os.clock())
end

function p.testGetCharacterId()
	return p._getCharacterId({name = 'Jeanne d\'Arc'})
end

function p.testGetOutfitLinkById()
	mw.log(p._getOutfitLinkById({id = 3710082000}))
	mw.log(p._getOutfitLinkById({id = 3710082000, full = 'yes'}))
end

function p.testGetCharacterLinkById()
	mw.log(p._getCharacterLinkById({id = 3030135000}))
	mw.log(p._getCharacterLinkById({id = 3040116000}))
end

return p