Minecraft Wiki
(Criou página com 'local p = {} -- List of special prefixes which should be handled by -- other modules (such as being moved outside links) p.prefixes = { 'Qualquer', 'Correspondente', 'Dani...')
 
(atualização do inglês - não aceitar mais imagem por img)
(25 revisões intermediárias por 2 usuários não estão sendo mostradas)
Linha 1: Linha 1:
 
local p = {}
 
local p = {}
   
  +
local i18n = {
-- List of special prefixes which should be handled by
 
  +
filename = 'Invicon $1',
-- other modules (such as being moved outside links)
 
  +
legacyFilename = 'Grid $1.png',
p.prefixes = {
 
  +
modLink = 'Mods/$1/$2',
'Qualquer',
 
  +
moduleAliases = [[Módulo:Inventory slot/Aliases]],
'Correspondente',
 
  +
moduleInvData = [[Módulo:InvSprite]],
'Danificado'
 
  +
moduleModData = 'Módulo:InvSprite/Mods/$1',
  +
moduleRandom = [[Módulo:Random]],
  +
moduleSprite = [[Módulo:Sprite]],
  +
-- Lista de prefixos especiais que devem ser tratados por
  +
-- outros módulos (Tais como links para ser movido fora)
  +
prefixes = {
  +
'Qualquer',
  +
any = 'Qualquer',
  +
},
  +
suffixes = {
  +
'correspondente',
  +
'danificado',
  +
'danificada',
  +
matching = 'correspondente',
  +
damaged = 'danificado',
  +
damagedfem = 'danificada',
  +
be = 'EB',
  +
eb = 'EB',
  +
lce = 'LCE',
  +
},
  +
templateFileUrl = 'FileUrl',
 
}
 
}
  +
p.i18n = i18n
  +
p.prefixes = i18n.prefixes
  +
p.suffixes = i18n.suffixes
   
  +
local random = require( i18n.moduleRandom ).random
  +
local sprite = require( i18n.moduleSprite ).sprite
  +
local aliases = mw.loadData( i18n.moduleAliases )
  +
local ids = mw.loadData( i18n.moduleInvData ).ids
  +
local modIds = {}
  +
local pageName = mw.title.getCurrentTitle().text
  +
  +
-- Performs a simple recursive clone of a table's values
  +
local function cloneTable( origTable )
  +
local newTable = {}
  +
for k, v in pairs( origTable ) do
  +
if type( v ) == 'table' then
  +
v = cloneTable( v )
  +
end
  +
newTable[k] = v
  +
end
  +
return newTable
  +
end
  +
  +
--[[Merges a list, or inserts a string
  +
or table into a table
  +
--]]
  +
local function mergeList( parentTable, content )
  +
local i = #parentTable + 1
  +
if content[1] then
  +
-- Merge list into table
  +
for _, v in ipairs( content ) do
  +
parentTable[i] = v
  +
i = i + 1
  +
end
  +
else
  +
-- Add strings or tables to table
  +
parentTable[i] = content
  +
end
  +
end
  +
  +
-- Creates the HTML for an item
  +
local function makeItem( frame, i, args )
  +
local item = mw.html.create( 'span' ):addClass( 'invslot-item' )
  +
if args.imgclass then
  +
item:addClass( args.imgclass )
  +
end
  +
if frame.name == '' then
  +
item:tag( 'br' )
  +
return item
  +
end
  +
local category
  +
local title = frame.title or mw.text.trim( args.title or '' )
  +
local mod = frame.mod
  +
local name = frame.name or ''
  +
local num = frame.num
  +
local description = frame.text
  +
  +
local img, idData
  +
if mod then
  +
local modData = modIds[mod]
  +
if not modData and mw.title.new( i18n.moduleModData:gsub( '%$1', mod ) ).exists then
  +
modData = mw.loadData( i18n.moduleModData:gsub( '%$1', mod ) )
  +
modIds[mod] = modData
  +
end
  +
if modData and modData[name] then
  +
idData = modData[name]
  +
else
  +
img = i18n.legacyFilename:gsub( '%$1', name .. ' (' .. mod .. ')' )
  +
end
  +
elseif ids[name] then
  +
idData = ids[name]
  +
elseif name:match( '\.gif$' ) or name:match( '\.png$' ) then
  +
img = i18n.filename:gsub( '%$1', name )
  +
-- Remove file extension from name
  +
name = name:sub( 0, -5 )
  +
end
  +
  +
if name:find( ' ' .. i18n.suffixes.damagedfem .. '$' ) then
  +
danificada = name:gsub( i18n.suffixes.damagedfem .. '$', '' )
  +
else
  +
danificada = nil
  +
end
  +
local link = args.link or ''
  +
if link == '' then
  +
if mod then
  +
link = i18n.modLink:gsub( '%$1', mod ):gsub( '%$2', name )
  +
else
  +
link = danificada or name:gsub( i18n.suffixes.damaged .. '$', '' )
  +
end
  +
elseif link:lower() == 'none' then
  +
link = nil
  +
end
  +
if link == pageName then
  +
link = nil
  +
end
  +
  +
local formattedTitle
  +
local plainTitle
  +
if title == '' then
  +
plainTitle = name
  +
elseif title:lower() ~= 'none' then
  +
plainTitle = title:gsub( '\\\\', '\' ):gsub( '\\&', '&' )
  +
  +
local formatPattern = '&[0-9a-fk-or]'
  +
if plainTitle:match( formatPattern ) then
  +
formattedTitle = title
  +
plainTitle = plainTitle:gsub( formatPattern, '' )
  +
end
  +
  +
if plainTitle == '' then
  +
plainTitle = name
  +
else
  +
plainTitle = plainTitle:gsub( '\', '\\' ):gsub( '&', '&' )
  +
end
  +
elseif link then
  +
if img then
  +
formattedTitle = ''
  +
else
  +
plainTitle = ''
  +
end
  +
end
  +
  +
item:attr{
  +
['data-minetip-title'] = formattedTitle,
  +
['data-minetip-text'] = description
  +
}
  +
  +
if img then
  +
-- & is re-escaped because mw.html treats attributes
  +
-- as plain text, but MediaWiki doesn't
  +
local escapedTitle = ( plainTitle or '' ):gsub( '&', '&' )
  +
item:addClass( 'invslot-item-image' )
  +
:wikitext( '[[Arquivo:', img, '|32x32px|link=', link or '', '|', escapedTitle, ']]' )
  +
else
  +
local image
  +
if mod then
  +
image = args.spritesheet or mod .. 'Sprite.png'
  +
end
  +
if link then
  +
item:wikitext( '[[', link, '|' )
  +
end
  +
local image, spriteCat = sprite{
  +
iddata = idData, title = plainTitle,
  +
image = image, data = 'InvSprite',
  +
nourl = args.nourl,
  +
}
  +
item:node( image )
  +
category = spriteCat
  +
end
  +
  +
if num and num > 1 and num < 1000 then
  +
if img and link then
  +
item:wikitext( '[[', link, '|' )
  +
end
  +
local number = item
  +
:tag( 'span' )
  +
:addClass( 'invslot-stacksize' )
  +
:attr{ title = plainTitle }
  +
:wikitext( num )
  +
if numStyle then
  +
number:cssText( numStyle )
  +
end
  +
if img and link then
  +
item:wikitext( ']]' )
  +
end
  +
end
  +
  +
if idData and link then
  +
item:wikitext( ']]' )
  +
end
  +
  +
item:wikitext( category )
  +
  +
return item
  +
end
  +
  +
-- Main entry point
 
function p.slot( f )
 
function p.slot( f )
 
local args = f.args or f
 
local args = f.args or f
Linha 15: Linha 212:
 
end
 
end
 
 
  +
if not args.parsed then
args[1] = mw.text.trim( args[1] or '' )
 
  +
args[1] = mw.text.trim( args[1] or '' )
  +
end
 
 
  +
local modData = {
-- Comment this next line out if you're not using aliases
 
local aliases = mw.loadData( 'Module:Inventory slot/Aliases' )
+
aliases = args.modaliases or '',
  +
default = args.mod
 
  +
}
local modAliases = args.modaliases or ''
 
if modAliases ~= '' then
+
if modData.aliases ~= '' then
modAliases = mw.loadData( 'Module:' .. modAliases )
+
modData.aliases = mw.loadData( 'Módulo:' .. modData.aliases )
 
else
 
else
modAliases = nil
+
modData.aliases = nil
 
end
 
end
  +
if args.mod == '' then
 
  +
modData.default = nil
if aliases or modAliases then
 
local frames = {}
 
for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do
 
local frameParts = p.getParts( frame, args.mod )
 
 
local id = frameParts.name
 
if frameParts.mod then
 
id = frameParts.mod .. ':' .. id
 
end
 
 
local alias
 
if modAliases and modAliases[id] then
 
alias = modAliases[id]
 
elseif aliases and aliases[id] then
 
alias = aliases[id]
 
end
 
 
if alias then
 
table.insert( frames, p.expandAlias( frameParts, alias ) )
 
else
 
table.insert( frames, frame )
 
end
 
end
 
 
args[1] = table.concat( frames, ';' )
 
 
end
 
end
 
 
local sprite
+
local frames
  +
if args.parsed then
local ids = mw.loadData( [[Module:InvSprite/IDs]] ).ids
 
  +
frames = args[1]
local modIds = {}
 
local animated = args[1]:find( ';' )
+
elseif args[1] ~= '' then
  +
local randomise = args.class == 'invslot-large' and 'never' or nil
local pageName = mw.title.getCurrentTitle().text
 
  +
frames = p.parseFrameText( args[1], randomise, false, modData )
  +
end
  +
local animated = frames and #frames > 1
 
local imgClass = args.imgclass
 
local imgClass = args.imgclass
 
local numStyle = args.numstyle
 
local numStyle = args.numstyle
Linha 71: Linha 249:
 
body:cssText( args.style )
 
body:cssText( args.style )
 
end
 
end
 
 
if ( args.default or '' ) ~= '' then
 
if ( args.default or '' ) ~= '' then
body:css( 'background-image', '{{FileUrl|' .. args.default .. '.png}}' )
+
body:css( 'background-image', f:expandTemplate{ title = i18n.templateFileUrl, args = { args.default .. '.png' } } )
 
end
 
end
 
 
  +
--mw.logObject( frames )
local first = true
 
  +
if not frames then
for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do
 
  +
body:tag( 'br' )
  +
return tostring( body )
  +
end
  +
  +
local activeFrame = frames.randomise == true and random( #frames ) or 1
  +
for i, frame in ipairs( frames ) do
 
local item
 
local item
  +
-- Table is a list, must contain subframes
if frame ~= '' or frame == '' and animated then
 
  +
if frame[1] then
item = body:tag( 'span' ):addClass( 'invslot-item' )
 
  +
item = body:tag( 'span' ):addClass( 'animated-subframe' )
if imgClass then
 
  +
local subActiveFrame = frame.randomise and random( #frame ) or 1
item:addClass( imgClass )
 
  +
for sI, sFrame in ipairs( frame ) do
  +
local sItem = makeItem( sFrame, sI, args )
  +
item:node( sItem )
  +
  +
if sI == subActiveFrame then
  +
sItem:addClass( 'animated-active' )
  +
end
 
end
 
end
end
 
 
if frame == '' then
 
( item or body ):tag( 'br' )
 
 
else
 
else
  +
item = makeItem( frame, i, args )
local category
 
  +
body:node( item )
local parts = p.getParts( frame, args.mod )
 
  +
end
local title = parts.title or mw.text.trim( args.title or '' )
 
  +
if i == activeFrame and animated then
local mod = parts.mod
 
  +
item:addClass( 'animated-active' )
local name = parts.name
 
  +
end
local num = parts.num
 
  +
end
local description = parts.text
 
  +
 
  +
return tostring( body )
local img, idData
 
  +
end
if mod then
 
  +
local modData = modIds[mod]
 
  +
--[[Parses the frame text into a table of frames and subframes,
if not modData and mw.title.new( 'Module:InvSprite/Mods/' .. mod .. '/IDs' ).exists then
 
  +
expanding aliases (and optionally retaining a reference), and
modData = mw.loadData( 'Module:InvSprite/Mods/' .. mod .. '/IDs' )
 
  +
deciding if the slot can be randomised
modIds[mod] = modData
 
  +
--]]
end
 
  +
function p.parseFrameText( framesText, randomise, aliasReference, modData )
if modData and modData[name] then
 
  +
local frames = { randomise = randomise }
idData = modData[name]
 
  +
local subframes = {}
else
 
  +
local subframe
img = name .. ' (' .. mod .. ')'
 
  +
local expandedAliases
end
 
  +
local splitFrames = mw.text.split( mw.text.trim( framesText ), '%s*;%s*' )
elseif ids[name] then
 
  +
for _, frameText in ipairs( splitFrames ) do
idData = ids[name]
 
  +
frameText = frameText:gsub( '^%s*{%s*', function()
else
 
img = name
+
subframe = true
  +
return ''
  +
end )
  +
if subframe then
  +
frameText = frameText:gsub( '%s*}%s*$', function()
  +
subframe = 'last'
  +
return ''
  +
end )
  +
end
  +
local frame = p.makeFrame( frameText, modData and modData.default )
  +
local newFrame = frame
  +
if aliases or modData.aliases then
  +
local id = frame.name
  +
if frame.mod then
  +
id = frame.mod .. ':' .. id
 
end
 
end
 
 
local link = args.link or ''
+
local alias = modData and modData.aliases and modData.aliases[id] or
  +
aliases and aliases[id]
if link == '' then
 
if mod then
+
if alias then
  +
newFrame = p.getAlias( alias, frame )
link = 'Mods/' .. mod .. '/' .. name
 
  +
if aliasReference then
else
 
  +
local curFrame = #frames + 1
link = name:gsub( '^Damaged ', '' )
 
  +
local aliasData = { frame = frame, length = #newFrame }
  +
if subframe then
  +
if not subframes.aliasReference then
  +
subframes.aliasReference = {}
  +
end
  +
subframes.aliasReference[#subframes + 1] = aliasData
  +
else
  +
if not expandedAliases then
  +
expandedAliases = {}
  +
end
  +
expandedAliases[curFrame] = aliasData
  +
end
 
end
 
end
elseif link:lower() == 'none' then
 
link = nil
 
 
end
 
end
  +
end
if link == pageName then
 
  +
link = nil
 
  +
if subframe then
  +
mergeList( subframes, newFrame )
  +
-- Randomise starting frame for "Qualquer *" aliases, as long as the alias is the only subframe
  +
if frames.randomise ~= 'never' and subframes.randomise == nil and
  +
frame.name:match( '^' .. i18n.prefixes.any .. ' ' ) then
  +
subframes.randomise = true
  +
else
  +
subframes.randomise = false
 
end
 
end
  +
if frames.randomise ~= 'never' then
 
  +
frames.randomise = false
local formattedTitle
 
  +
end
local plainTitle
 
if title == '' then
+
if subframe == 'last' then
  +
-- No point having a subframe containing a single frame,
plainTitle = name
 
  +
-- or the subframe being the only frame
elseif title:lower() ~= 'none' then
 
  +
if #subframes == 1 or #splitFrames == i and #frames == 0 then
plainTitle = title:gsub( '\\\\', '&#92;' ):gsub( '\\&', '&#38;' )
 
  +
mergeList( frames, subframes )
 
local formatPattern = '&[0-9a-fk-or]'
 
if plainTitle:match( formatPattern ) then
 
formattedTitle = title
 
plainTitle = plainTitle:gsub( formatPattern, '' )
 
end
 
 
if plainTitle == '' then
 
plainTitle = name
 
 
else
 
else
  +
table.insert( frames, subframes )
plainTitle = plainTitle:gsub( '&#92;', '\\' ):gsub( '&#38;', '&' )
 
end
 
elseif link then
 
if img then
 
formattedTitle = ''
 
else
 
plainTitle = ''
 
 
end
 
end
  +
subframes = {}
  +
subframe = nil
 
end
 
end
+
else
  +
-- Randomise starting frame for "Qualquer *" aliases, as long as the alias is the only frame
item:attr{
 
  +
if frames.randomise == nil and frame.name:match( '^' .. i18n.prefixes.any .. ' ' ) then
['data-minetip-title'] = formattedTitle,
 
  +
frames.randomise = true
['data-minetip-text'] = description
 
  +
elseif frames.randomise ~= 'never' then
}
 
  +
frames.randomise = false
 
if img then
 
-- & is re-escaped because mw.html treats attributes
 
-- as plain text, but MediaWiki doesn't
 
local escapedTitle = ( plainTitle or '' ):gsub( '&', '&#38;' )
 
item:addClass( 'invslot-item-image' )
 
:wikitext( '[[File:Grid ', img, '.png|32x32px|link=', link or '', '|', escapedTitle, ']]' )
 
else
 
if not sprite then
 
sprite = require( [[Module:Sprite]] ).sprite
 
end
 
local image
 
if mod then
 
image = args.spritesheet or mod .. 'Sprite.png'
 
end
 
if link then
 
item:wikitext( '[[', link, '|' )
 
end
 
local image, spriteCat = sprite{
 
iddata = idData, title = plainTitle,
 
image = image, settings = 'InvSprite'
 
}
 
item:node( image )
 
category = spriteCat
 
 
end
 
end
  +
mergeList( frames, newFrame )
 
if num and num > 1 and num < 1000 then
 
if img and link then
 
item:wikitext( '[[', link, '|' )
 
end
 
local number = item
 
:tag( 'span' )
 
:addClass( 'invslot-stacksize' )
 
:attr{ title = plainTitle }
 
:wikitext( num )
 
if numStyle then
 
number:cssText( numStyle )
 
end
 
if img and link then
 
item:wikitext( ']]' )
 
end
 
end
 
 
if idData and link then
 
item:wikitext( ']]' )
 
end
 
 
item:wikitext( category )
 
end
 
 
if first then
 
if animated and item then
 
item:addClass( 'active' )
 
end
 
first = false
 
 
end
 
end
 
end
 
end
 
 
  +
frames.aliasReference = expandedAliases
return tostring( body )
 
  +
  +
return frames
 
end
 
end
   
  +
--[[Returns a new table with the parts of the parent frame
function p.expandAlias( frameParts, alias )
 
  +
added to the alias
-- If the frame has no parts, we can just return the alias as-is
 
  +
--]]
if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then
 
  +
function p.getAlias( aliasFrames, parentFrame )
return alias
 
  +
-- If alias is just a name, return the parent frame with the new name
  +
if type( aliasFrames ) == 'string' then
  +
local expandedFrame = mw.clone( parentFrame )
  +
expandedFrame.name = aliasFrames
  +
return { expandedFrame }
  +
end
  +
  +
-- Single frame alias, put in list
  +
if aliasFrames.name then
  +
aliasFrames = { aliasFrames }
 
end
 
end
 
 
 
local expandedFrames = {}
 
local expandedFrames = {}
for aliasFrame in mw.text.gsplit( alias, '%s*;%s*' ) do
+
for i, aliasFrame in ipairs( aliasFrames ) do
  +
local expandedFrame
local aliasParts = p.getParts( aliasFrame )
 
  +
if type( aliasFrame ) == 'string' then
aliasParts.title = frameParts.title or aliasParts.title or ''
 
  +
expandedFrame = { name = aliasFrame }
aliasParts.mod = frameParts.mod or aliasParts.mod or 'Minecraft'
 
  +
else
aliasParts.num = frameParts.num or aliasParts.num or ''
 
  +
expandedFrame = cloneTable( aliasFrame )
aliasParts.text = frameParts.text or aliasParts.text or ''
 
  +
end
  +
expandedFrame.title = parentFrame.title or expandedFrame.title
  +
expandedFrame.mod = parentFrame.mod or expandedFrame.mod
  +
expandedFrame.num = parentFrame.num or expandedFrame.num
  +
expandedFrame.text = parentFrame.text or expandedFrame.text
 
 
table.insert( expandedFrames, string.format(
+
expandedFrames[i] = expandedFrame
'[%s]%s:%s,%s[%s]',
 
aliasParts.title, aliasParts.mod, aliasParts.name, aliasParts.num, aliasParts.text
 
) )
 
 
end
 
end
 
 
return table.concat( expandedFrames, ';' )
+
return expandedFrames
 
end
 
end
   
function p.getParts( frame, mod )
+
function p.expandAlias( parentFrame, alias )
  +
return p.getAlias( alias, parentFrame )
local parts = {}
 
  +
end
parts.title = frame:match( '^%[%s*([^%]]+)%s*%]' )
 
  +
  +
function p.stringifyFrame( frame )
  +
if not frame.name then
  +
return ''
  +
end
  +
return string.format(
  +
'[%s]%s:%s,%s[%s]',
  +
frame.title or '',
  +
frame.mod or 'Minecraft',
  +
frame.name,
  +
frame.num or '',
  +
frame.text or ''
  +
)
  +
end
  +
  +
function p.stringifyFrames( frames )
  +
for i, frame in ipairs( frames ) do
  +
frames[i] = p.stringifyFrame( frame )
  +
end
  +
return table.concat( frames, ';' )
  +
end
  +
  +
-- Splits up the frame text into its parts
  +
function p.makeFrame( frameText, mod )
  +
-- Simple frame with no parts
  +
if not frameText:match( '[%[:,]' ) then
  +
return {
  +
mod = mod,
  +
name = mw.text.trim( frameText ),
  +
}
  +
end
 
 
parts.mod = mw.text.trim( frame:match( '([^:%]]+):' ) or mod or '' )
+
frameText = frameText:gsub( '%s*([%[%]:,;])%s*', '%1' )
 
 
  +
local frame = {}
  +
frame.title = frameText:match( '^%[([^%]]+)%]' )
  +
  +
frame.mod = frameText:match( '([^:%]]+):' ) or mod
 
local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
 
local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
if parts.mod == '' or vanilla[mw.ustring.lower( parts.mod )] then
+
if frame.mod and vanilla[mw.ustring.lower( frame.mod )] or frame.mod == '' then
parts.mod = nil
+
frame.mod = nil
 
end
 
end
 
 
local nameStart = ( frame:find( ':' ) or frame:find( '%]' ) or 0 ) + 1
+
local nameStart = ( frameText:find( ':' ) or frameText:find( '%]' ) or 0 ) + 1
if nameStart - 1 == #frame then
+
if nameStart - 1 == #frameText then
 
nameStart = 1
 
nameStart = 1
 
end
 
end
parts.name = mw.text.trim( frame:sub( nameStart, ( frame:find( '[,%[]', nameStart ) or 0 ) - 1 ) )
+
frame.name = frameText:sub( nameStart, ( frameText:find( '[,%[]', nameStart ) or 0 ) - 1 )
 
 
parts.num = math.floor( frame:match( ',%s*(%d+)' ) or 0 )
+
frame.num = math.floor( frameText:match( ',(%d+)' ) or 0 )
if parts.num == 0 then
+
if frame.num == 0 then
parts.num = nil
+
frame.num = nil
 
end
 
end
 
 
parts.text = frame:match( '%[%s*([^%]]+)%s*%]$' )
+
frame.text = frameText:match( '%[([^%]]+)%]$' )
 
 
return parts
+
return frame
  +
end
  +
function p.getParts( frameText, mod )
  +
return p.makeFrame( frameText, mod )
 
end
 
end
 
 

Edição das 14h12min de 18 de novembro de 2020

Este módulo implementa {{inventory slot}}.

Dependências

[ver | editar | histórico | purgar]A documentação acima é transcluída de Módulo:Inventory slot/doc.
local p = {}

local i18n = {
	filename = 'Invicon $1',
	legacyFilename = 'Grid $1.png',
	modLink = 'Mods/$1/$2',
	moduleAliases = [[Módulo:Inventory slot/Aliases]],
	moduleInvData = [[Módulo:InvSprite]],
	moduleModData = 'Módulo:InvSprite/Mods/$1',
	moduleRandom = [[Módulo:Random]],
	moduleSprite = [[Módulo:Sprite]],
	-- Lista de prefixos especiais que devem ser tratados por
	-- outros módulos (Tais como links para ser movido fora)
	prefixes = {
		'Qualquer',
		any = 'Qualquer',
	},
	suffixes = {
		'correspondente',
		'danificado',
		'danificada',
		matching = 'correspondente',
		damaged = 'danificado',
		damagedfem = 'danificada',
		be = 'EB',
		eb = 'EB',
		lce = 'LCE',
	},
	templateFileUrl = 'FileUrl',
}
p.i18n = i18n
p.prefixes = i18n.prefixes
p.suffixes = i18n.suffixes

local random = require( i18n.moduleRandom ).random
local sprite = require( i18n.moduleSprite ).sprite
local aliases = mw.loadData( i18n.moduleAliases )
local ids = mw.loadData( i18n.moduleInvData ).ids
local modIds = {}
local pageName = mw.title.getCurrentTitle().text

-- Performs a simple recursive clone of a table's values
local function cloneTable( origTable )
	local newTable = {}
	for k, v in pairs( origTable ) do
		if type( v ) == 'table' then
			v = cloneTable( v )
		end
		newTable[k] = v
	end
	return newTable
end

--[[Merges a list, or inserts a string
	or table into a table
--]]
local function mergeList( parentTable, content )
	local i = #parentTable + 1
	if content[1] then
		-- Merge list into table
		for _, v in ipairs( content ) do
			parentTable[i] = v
			i = i + 1
		end
	else
		-- Add strings or tables to table
		parentTable[i] = content
	end
end

-- Creates the HTML for an item
local function makeItem( frame, i, args )
	local item = mw.html.create( 'span' ):addClass( 'invslot-item' )
	if args.imgclass then
		item:addClass( args.imgclass )
	end
	if frame.name == '' then
		item:tag( 'br' )
		return item
	end
	local category
	local title = frame.title or mw.text.trim( args.title or '' )
	local mod = frame.mod
	local name = frame.name or ''
	local num = frame.num
	local description = frame.text
	
	local img, idData
	if mod then
		local modData = modIds[mod]
		if not modData and mw.title.new( i18n.moduleModData:gsub( '%$1', mod ) ).exists then
			modData = mw.loadData( i18n.moduleModData:gsub( '%$1', mod ) )
			modIds[mod] = modData
		end
		if modData and modData[name] then
			idData = modData[name]
		else
			img = i18n.legacyFilename:gsub( '%$1', name .. ' (' .. mod .. ')' )
		end
	elseif ids[name] then
		idData = ids[name]
	elseif name:match( '\.gif$' ) or name:match( '\.png$' ) then
		img = i18n.filename:gsub( '%$1', name )
		-- Remove file extension from name
		name = name:sub( 0, -5 )
	end
	
	if name:find( ' ' .. i18n.suffixes.damagedfem .. '$' ) then
		danificada = name:gsub( i18n.suffixes.damagedfem .. '$', '' )
	else
		danificada = nil
	end
	local link = args.link or ''
	if link == '' then
		if mod then
			link = i18n.modLink:gsub( '%$1', mod ):gsub( '%$2', name )
		else
			link = danificada or name:gsub( i18n.suffixes.damaged .. '$', '' )
		end
	elseif link:lower() == 'none' then
		link = nil
	end
	if link == pageName then
		link = nil
	end
	
	local formattedTitle
	local plainTitle
	if title == '' then
		plainTitle = name
	elseif title:lower() ~= 'none' then
		plainTitle = title:gsub( '\\\\', '&#92;' ):gsub( '\\&', '&#38;' )
		
		local formatPattern = '&[0-9a-fk-or]'
		if plainTitle:match( formatPattern ) then
			formattedTitle = title
			plainTitle = plainTitle:gsub( formatPattern, '' )
		end
		
		if plainTitle == '' then
			plainTitle = name
		else
			plainTitle = plainTitle:gsub( '&#92;', '\\' ):gsub( '&#38;', '&' )
		end
	elseif link then
		if img then
			formattedTitle = ''
		else
			plainTitle = ''
		end
	end
	
	item:attr{
		['data-minetip-title'] = formattedTitle,
		['data-minetip-text'] = description
	}
	
	if img then
		-- & is re-escaped because mw.html treats attributes
		-- as plain text, but MediaWiki doesn't
		local escapedTitle = ( plainTitle or '' ):gsub( '&', '&#38;' )
		item:addClass( 'invslot-item-image' )
			:wikitext( '[[Arquivo:', img, '|32x32px|link=', link or '', '|', escapedTitle, ']]' )
	else
		local image
		if mod then
			image = args.spritesheet or mod .. 'Sprite.png'
		end
		if link then
			item:wikitext( '[[', link, '|' )
		end
		local image, spriteCat = sprite{
			iddata = idData, title = plainTitle,
			image = image, data = 'InvSprite',
            nourl = args.nourl,
		}
		item:node( image )
		category = spriteCat
	end
	
	if num and num > 1 and num < 1000 then
		if img and link then
			item:wikitext( '[[', link, '|' )
		end
		local number = item
			:tag( 'span' )
				:addClass( 'invslot-stacksize' )
				:attr{ title = plainTitle }
				:wikitext( num )
		if numStyle then
			number:cssText( numStyle )
		end
		if img and link then
			item:wikitext( ']]' )
		end
	end
	
	if idData and link then
		item:wikitext( ']]' )
	end
	
	item:wikitext( category )
	
	return item
end

-- Main entry point
function p.slot( f )
	local args = f.args or f
	if f == mw.getCurrentFrame() and args[1] == nil then
		args = f:getParent().args
	end
	
	if not args.parsed then
		args[1] = mw.text.trim( args[1] or '' )
	end
	
	local modData = {
		aliases = args.modaliases or '',
		default = args.mod
	}
	if modData.aliases ~= '' then
		modData.aliases = mw.loadData( 'Módulo:' .. modData.aliases )
	else
		modData.aliases = nil
	end
	if args.mod == '' then
		modData.default = nil
	end
	
	local frames
	if args.parsed then
		frames = args[1]
	elseif args[1] ~= '' then
		local randomise = args.class == 'invslot-large' and 'never' or nil
		frames = p.parseFrameText( args[1], randomise, false, modData )
	end
	local animated = frames and #frames > 1
	local imgClass = args.imgclass
	local numStyle = args.numstyle
	local body = mw.html.create( 'span' ):addClass( 'invslot' ):css{ ['vertical-align'] = args.align }
	if animated then
		body:addClass( 'animated' )
	end
	if args.class then
		body:addClass( args.class )
	end
	if args.style then
		body:cssText( args.style )
	end
	if ( args.default or '' ) ~= '' then
		body:css( 'background-image', f:expandTemplate{ title = i18n.templateFileUrl, args = { args.default .. '.png' } } )
	end
	
	--mw.logObject( frames )
	if not frames then
		body:tag( 'br' )
		return tostring( body )
	end
	
	local activeFrame = frames.randomise == true and random( #frames ) or 1
	for i, frame in ipairs( frames ) do
		local item
		-- Table is a list, must contain subframes
		if frame[1] then
			item = body:tag( 'span' ):addClass( 'animated-subframe' )
			local subActiveFrame = frame.randomise and random( #frame ) or 1
			for sI, sFrame in ipairs( frame ) do
				local sItem = makeItem( sFrame, sI, args )
				item:node( sItem )
				
				if sI == subActiveFrame then
					sItem:addClass( 'animated-active' )
				end
			end
		else
			item = makeItem( frame, i, args )
			body:node( item )
		end
		if i == activeFrame and animated then
			item:addClass( 'animated-active' )
		end
	end
	
	return tostring( body )
end

--[[Parses the frame text into a table of frames and subframes,
	expanding aliases (and optionally retaining a reference), and
	deciding if the slot can be randomised
--]]
function p.parseFrameText( framesText, randomise, aliasReference, modData )
	local frames = { randomise = randomise }
	local subframes = {}
	local subframe
	local expandedAliases
	local splitFrames = mw.text.split( mw.text.trim( framesText ), '%s*;%s*' )
	for _, frameText in ipairs( splitFrames ) do
		frameText = frameText:gsub( '^%s*{%s*', function()
			subframe = true
			return ''
		end )
		if subframe then
			frameText = frameText:gsub( '%s*}%s*$', function()
				subframe = 'last'
				return ''
			end )
		end
		local frame = p.makeFrame( frameText, modData and modData.default )
		local newFrame = frame
		if aliases or modData.aliases then
			local id = frame.name
			if frame.mod then
				id = frame.mod .. ':' .. id
			end
			
			local alias = modData and modData.aliases and modData.aliases[id] or
				aliases and aliases[id]
			if alias then
				newFrame = p.getAlias( alias, frame )
				if aliasReference then
					local curFrame = #frames + 1
					local aliasData = { frame = frame, length = #newFrame }
					if subframe then
						if not subframes.aliasReference then
							subframes.aliasReference = {}
						end
						subframes.aliasReference[#subframes + 1] = aliasData
					else
						if not expandedAliases then
							expandedAliases = {}
						end
						expandedAliases[curFrame] = aliasData
					end
				end
			end
		end
		
		if subframe then
			mergeList( subframes, newFrame )
			-- Randomise starting frame for "Qualquer *" aliases, as long as the alias is the only subframe
			if frames.randomise ~= 'never' and subframes.randomise == nil and
				frame.name:match( '^' .. i18n.prefixes.any .. ' ' ) then
				subframes.randomise = true
			else
				subframes.randomise = false
			end
			if frames.randomise ~= 'never' then
				frames.randomise = false
			end
			if subframe == 'last' then
				-- No point having a subframe containing a single frame,
				-- or the subframe being the only frame
				if #subframes == 1 or #splitFrames == i and #frames == 0 then
					mergeList( frames, subframes )
				else
					table.insert( frames, subframes )
				end
				subframes = {}
				subframe = nil
			end
		else
			-- Randomise starting frame for "Qualquer *" aliases, as long as the alias is the only frame
			if frames.randomise == nil and frame.name:match( '^' .. i18n.prefixes.any .. ' ' ) then
				frames.randomise = true
			elseif frames.randomise ~= 'never' then
				frames.randomise = false
			end
			mergeList( frames, newFrame )
		end
	end
	
	frames.aliasReference = expandedAliases
	
	return frames
end

--[[Returns a new table with the parts of the parent frame
	added to the alias
--]]
function p.getAlias( aliasFrames, parentFrame )
	-- If alias is just a name, return the parent frame with the new name
	if type( aliasFrames ) == 'string' then
		local expandedFrame = mw.clone( parentFrame )
		expandedFrame.name = aliasFrames
		return { expandedFrame }
	end
	
	-- Single frame alias, put in list
	if aliasFrames.name then
		aliasFrames = { aliasFrames }
	end
	
	local expandedFrames = {}
	for i, aliasFrame in ipairs( aliasFrames ) do
		local expandedFrame
		if type( aliasFrame ) == 'string' then
			expandedFrame = { name = aliasFrame }
		else
			expandedFrame = cloneTable( aliasFrame )
		end
		expandedFrame.title = parentFrame.title or expandedFrame.title
		expandedFrame.mod = parentFrame.mod or expandedFrame.mod
		expandedFrame.num = parentFrame.num or expandedFrame.num
		expandedFrame.text = parentFrame.text or expandedFrame.text
		
		expandedFrames[i] = expandedFrame
	end
	
	return expandedFrames
end

function p.expandAlias( parentFrame, alias )
	return p.getAlias( alias, parentFrame )
end

function p.stringifyFrame( frame )
	if not frame.name then
		return ''
	end
	return string.format(
		'[%s]%s:%s,%s[%s]',
		frame.title or '',
		frame.mod or 'Minecraft',
		frame.name,
		frame.num or '',
		frame.text or ''
	)
end

function p.stringifyFrames( frames )
	for i, frame in ipairs( frames ) do
		frames[i] = p.stringifyFrame( frame )
	end
	return table.concat( frames, ';' )
end

-- Splits up the frame text into its parts
function p.makeFrame( frameText, mod )
	-- Simple frame with no parts
	if not frameText:match( '[%[:,]' ) then
		return {
			mod = mod,
			name = mw.text.trim( frameText ),
		}
	end
	
	frameText = frameText:gsub( '%s*([%[%]:,;])%s*', '%1' )
	
	local frame = {}
	frame.title = frameText:match( '^%[([^%]]+)%]' )
	
	frame.mod = frameText:match( '([^:%]]+):' ) or mod
	local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
	if frame.mod and vanilla[mw.ustring.lower( frame.mod )] or frame.mod == '' then
		frame.mod = nil
	end
	
	local nameStart = ( frameText:find( ':' ) or frameText:find( '%]' ) or 0 ) + 1
	if nameStart - 1 == #frameText then
		nameStart = 1
	end
	frame.name = frameText:sub( nameStart, ( frameText:find( '[,%[]', nameStart ) or 0 ) - 1 )
	
	frame.num = math.floor( frameText:match( ',(%d+)' ) or 0 )
	if frame.num == 0 then
		frame.num = nil
	end
	
	frame.text = frameText:match( '%[([^%]]+)%]$' )
	
	return frame
end
function p.getParts( frameText, mod )
	return p.makeFrame( frameText, mod )
end
 
return p