FANDOM


local CharacterInfobox={}
 
local HF = require("Module:HF")
 
--[[
---- PRIVATE METHODS
]]-- 
 
local Plural = function( s )
  -- Be careful! This function works only for regular plurals!
 
  local last1, last2, last3 = string.sub( s, -1, -1 ), string.sub( s, -2, -1 ), string.sub( s, -3, -1 )
 
  if last1 == "y" then
    s = string.sub( s, 1, -2 ) .. "ies"
  elseif last1 == "s" or last1 == "x" or last1 == "z" or last2 == "ch" or last2 == "sh" then
    s = s .. "es"    
  elseif last1 == "f" then
    s = string.sub( s, 1, -2 ) .. "ves"
  elseif last2 == "fe" then
    s = string.sub( s, 1, -3 ) .. "ves"
  else
    s = s .. "s"
  end
 
  return s
end
 
local AddZeros = function( s, len )
  local output = ""
 
  local sLength = string.len( tostring( s ) )
  local diff = tonumber( len ) - tonumber( sLength )
 
  if diff > 0 then
    for i = 1, diff do
      output = output .. "0"
    end
  end
 
  output = output .. s
 
  return output
end
 
local ExternalLink = function( link, text, plain )
  local output = "[" .. link .. " " .. text .. "]"
 
  if plain == true then
    output = "<span class=\"plainlinks\">" .. output .. "</span>"
  end  
 
  return output
end
 
local CategoryLink = function( category, sort, text )
  local output = ""
  if not HF.isempty( text ) then
    output = string.format('[['..':%s:%s|%s]][['..'%s:%s|%s]]', 'Category', category, text, 'Category', category, sort)
  else 
    output = string.format('[['..'%s:%s|%s]]', 'Category', category, sort)
  end
  return output
end
 
local Link = function( link, text )
  local output = "[[" .. link
 
  if not HF.isempty( text ) then
    output = output .. "|" .. text
  end
 
  output = output .. "]]"
 
  return output
end
 
local WeightSubcategory = function( weight )
  local subcategory = ""  
if
   weight < 100 then
    subcategory = 0
  elseif weight >= 100 and weight < 150 then
    subcategory = 100
  elseif weight >= 150 and weight < 200 then
    subcategory = 150
  elseif weight >= 200 and weight < 300 then
    subcategory = 200
  elseif weight >= 300 and weight < 400 then
    subcategory = 300
  elseif weight >= 400 and weight < 500 then
    subcategory = 400
  elseif weight >= 500 then
    subcategory = 500
  end
 
  return subcategory
end
 
local EyesCategory = function( eyes, vars )
  local output = ""
 
  local eyes   = HF.firstToUpper( eyes )
  local eyeslc = string.lower( eyes )
 
  if eyeslc == "none" or eyeslc == "n/a" or eyeslc == "no eyes" then
    output = CategoryLink( "No Eyes", vars.Pagename, "No Eyes" ) 
  else
    if mw.site.stats.pagesInCategory( eyes .. " Eyes", "pages" ) > 0 then
      output = CategoryLink( eyes .. " Eyes", vars.Pagename, eyes )
    else
      output = eyes
    end
  end
 
  return output
end
 
local HairCategory = function( hair, vars )
  local output = ""
 
  local hair   = HF.firstToUpper( hair )
  local hairlc = string.lower( hair )
 
  if     hairlc == "gray" then
    hair = "Grey"
  elseif hairlc == "blonde" then
    hair = "Blond"
  elseif hairlc == "strawberry blonde" then
    hair = "Strawberry Blond"
  end
 
  if     hairlc == "bald" then
    output = CategoryLink( hair, vars.Pagename, hair )
  elseif hairlc == "none" or hairlc == "no hair" then
    output = CategoryLink( "No Hair", vars.Pagename, "No Hair" )
  else
    if mw.site.stats.pagesInCategory( hair .. " Hair", "pages" ) > 0 then
      output = CategoryLink( hair .. " Hair", vars.Pagename, hair )
    else
      output = hair
    end
  end
 
  return output
end
 
local UniverseCategory = function( value, vars )
  local output = ""
 
    local UniverseNo    = string.match( value, "%d+" )
    local UniverseTRN   = string.match( string.lower( value ), "trn" )
    local UniverseValid = value
 
    if UniverseNo ~= nil then
      output = output .. Link( UniverseValid )
      output = output .. CategoryLink( UniverseValid .. " Characters", vars.Pagename, "" )
    else
      output = output .. Link( value )
      output = output .. CategoryLink( value .. " Characters", vars.Pagename, "" )
    end
 
  return output
end
 
local CategoriesFromKeywords = function( fieldValue, valid, exceptions, vars )
  local output = ""
 
  for key, value in pairs(valid) do
 
    -- Continue only if a word is found
    if string.find( string.lower(fieldValue), key ) ~= nil then
      -- Get all of the matches
      local matches = string.gmatch( fieldValue, key )
 
      -- Check if a keyword has exceptions
      if type( exceptions.keys ) == "table" then
        -- Check if any of the matches is not an exception
        for exception in pairs( exceptions.key ) do
          for keyword in matches do
            if string.find( keyword, exception ) == nil then
 
                -- If a word doesn't match exceptions - add a link for each element of a value array to the output
                for i, category in ipairs( value ) do
                  output = output .. CategoryLink( category, vars.Pagename, "" )
                end
              end
            end  
        end
      else
        for i, category in ipairs( value ) do
          output = output .. CategoryLink( category, vars.Pagename, "" )
        end
      end
 
    end
  end
 
  return output
end
 
--[[
---- PUBLIC METHODS
]]-- 
 
function CharacterInfobox.InfoButton( field, vars )
  if HF.isempty( field.buttonsize ) then field.buttonsize = "10px" end
 
  local output = '<span style="line-height:normal; float:left; position:relative; top:4px;">'
  output = output .. '[[File:Information-silk.png|' .. field.buttonsize
  output = output .. '|link=Click here for help with this field#' .. field.Label .. ']]'
  output = output .. '</span><span style="float: left; position: relative; left: 5px;">' .. field.Label .. '</span>'
 
  return output
end
 
function CharacterInfobox.getTitle( field, vars )
  local title = field.Value
 
  if not HF.isempty(field.Title) then
    title = field.Title
  elseif not HF.isempty(field.CurrentAlias) then
    title = field.CurrentAlias
  elseif not HF.isempty(field.CurrentAliasRef) then
    title = field.CurrentAliasRef
  elseif not HF.isempty(field.RealName) then
    title = field.RealName
  end
 
  local link = '<span style="position:relative; float:right; font-size:70%;">[[File:Help.png|link=Help:Template Fields#Character Template|Character Template Help]]</span>'
  local titleObj = mw.title.new( title )
 
  if type(titleObj) ~= nil then
    if titleObj.exists then
      link = link .. Link( title, "" )
    else
      link = link .. title
    end
  else
    link = link .. title
  end
 
  if HF.isempty( field.Death ) then
    link = link .. CategoryLink( "Living Characters", vars.Pagename, "" )
  end
 
  return link
end
 
function CharacterInfobox.MainImage( field, vars )
  if HF.isempty( field.ImageText ) then field.ImageText = vars.Pagename end
 
  local output = '[[File:' .. field.Value .. '|' .. field.ImageText .. ']]'
 
  return output
end
 
function CharacterInfobox.MainImageLabel( field, vars )
  if HF.isempty( field.Gallery ) then field.Gallery = vars.Pagename .. "/Gallery" end
 
  return Link( field.Gallery, field.Label )
end
 
function CharacterInfobox.RealName( field, vars )
  local output = ""
 
  if HF.isempty( field.ValueReal ) then
    output = field.Value
  else
    if string.find( field.ValueReal, "%[%[.+%]%]" ) == nil then
      link = Link( field.ValueReal, "" )
    else
      link = field.ValueReal
    end
 
    output = output .. link
 
    if not HF.isempty( field.Value2 ) and not HF.isempty( field.ValueRef ) then
      output = output .. " " .. field.Value2 .. " " .. field.ValueRef
    end
  end
 
  return output
end
 
function CharacterInfobox.CurrentAlias( field, vars )
  local output = field.Value
    if not HF.isempty( field.ValueRef ) then output = output .. "&nbsp;" .. field.ValueRef end
  return output
end
 
function CharacterInfobox.Alignment( field, vars )
  local output = ""
  local alignment = ""
  if not HF.isempty( field.Value ) then
    if field.Value:lower() == "evil" or field.Value:lower() == "bad" then
      alignment = "Bad"
    elseif field.Value:lower() == "neutral" then
      alignment = "Neutral"
    elseif field.Value:lower() == "good" then
      alignment = "Good"
    elseif field.Value:lower() == "civilian" then
      alignment = "Civilian"
    end
    output = CategoryLink( alignment .. " Characters", alignment .. " Characters", alignment )
  else
    output = ""
  end
 
  return output
end
 
function CharacterInfobox.Identity( field, vars )
  local output = ""
  if not HF.isempty( field.Value ) then
    local category = field.Value .. " Identity"
    output = CategoryLink( category, category, category )
  end
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
  return output
end
 
function CharacterInfobox.Race( field, vars )
  local output    = ""
  local raceTable = mw.loadData('Module:CharacterInfoboxRace')
  local valid, substitutes = raceTable.valid, raceTable.substitutes
 
  -- Check for multiple Citizenships separated with commas
  local races = HF.explode( ',', field.Value )
 
  for i, race in ipairs( races ) do
    race = HF.trim( race )
 
    -- 1. Check if it's a valid race with a plural form. If yes - add category links
    if type( valid[race] ) == "string" then
      output = output .. CategoryLink( valid[race], vars.Pagename, race ) .. ", "
 
    else
    -- 2. If it's not valid, check for a possible substitution
      local firstLetter, found = string.lower( string.sub( race, 1, 1 ) ), false
 
      if type(substitutes[firstLetter]) == "table" then
       for pattern, sub in pairs( substitutes[firstLetter] ) do
         if string.find( string.lower( race ), pattern ) ~= nil then
           found = true
 
           local subValid  = sub
           local subPlural = valid[subValid]
 
           output = output .. CategoryLink( subPlural, vars.Pagename, subValid ) .. ", "
 
           -- Since we only need one substitution, break loop
           break
         end
       end
      else
        for letter, subs in pairs( substitutes ) do
          for pattern, sub in pairs( subs ) do
            if string.find( string.lower( race ), pattern ) ~= nil then
             found = true
 
             local subValid  = sub
             local subPlural = valid[subValid]
 
             output = output .. CategoryLink( subPlural, vars.Pagename, subValid ) .. ", "
 
             -- Since we only need one substitution, break loop
             break
           end
          end
        end
      end
 
      -- 3. If no substitution is found - fallback to a common grammar rules and add a page to a Category:Needs valid race
      if not found then
        output = output .. CategoryLink( Plural( race ), vars.Pagename, race )
        output = output .. CategoryLink( "Needs valid race", vars.Pagename, "" ) .. ", "
      end
    end
  end
 
  -- Sanitize output, remove the last comma and space
  if string.sub( output, -1, -1 ) == "," then
    output = string.sub( output, 1, -2 )
  end
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 )
  end
 
  -- If Citizenship2 or CitizenshipRef is provided - concatenate them to the output
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
 
  if not HF.isempty( field.ValueRef ) then
    output = output .. " " .. field.ValueRef
  end
 
  return output
end
 
function CharacterInfobox.Citizenship( field, vars )
  local output    = ""
  local ctznTable = mw.loadData('Module:CharacterInfoboxCitizenship')
  local valid, substitutes = ctznTable.valid, ctznTable.substitutes
 
  -- Check for multiple Citizenships separated with commas
  local citizenships = HF.explode( ',', field.Value )
 
  for i, citizenship in ipairs( citizenships ) do
    citizenship = HF.trim( citizenship )
 
    -- 1. Check if it's a valid citizenship with a plural form. If yes - add category links
    if type( valid[citizenship] ) == "string" then
      output = output .. CategoryLink( valid[citizenship], vars.Pagename, citizenship ) .. ", "
 
    else
    -- 2. If it's not valid, check for a possible substitution
      local firstLetter, found = string.lower( string.sub( citizenship, 1, 1 ) ), false
 
      if type(substitutes[firstLetter]) == "table" then
       for pattern, sub in pairs( substitutes[firstLetter] ) do
         if string.find( string.lower( citizenship ), pattern ) ~= nil then
           found = true
 
           local subValid  = sub
           local subPlural = valid[subValid]
 
           output = output .. CategoryLink( subPlural, vars.Pagename, subValid ) .. ", "
 
           -- Since we only need one substitution, break loop
           break
         end
       end
      else
        for letter, subs in pairs( substitutes ) do
          for pattern, sub in pairs( subs ) do
            if string.find( string.lower( citizenship ), pattern ) ~= nil then
             found = true
 
             local subValid  = sub
             local subPlural = valid[subValid]
 
             output = output .. CategoryLink( subPlural, vars.Pagename, subValid ) .. ", "
 
             -- Since we only need one substitution, break loop
             break
           end
          end
        end
      end
 
      -- 3. If no substitution is found - fallback to a common grammar rules and add a page to a Category:Needs valid citizenship
      if not found then
        output = output .. CategoryLink( Plural( citizenship ), vars.Pagename, citizenship )
        output = output .. CategoryLink( "Needs valid citizenship", vars.Pagename, "" ) .. ", "
      end
    end
  end
 
  -- Sanitize output, remove the last comma and space
  if string.sub( output, -1, -1 ) == "," then
    output = string.sub( output, 1, -2 )
  end
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 )
  end
 
  -- If Citizenship2 or CitizenshipRef is provided - concatenate them to the output
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
 
  if not HF.isempty( field.ValueRef ) then
    output = output .. " " .. field.ValueRef
  end
 
  return output
end
 
function CharacterInfobox.MaritalStatus( field, vars )
  local statuses = HF.explode( ";", field.Value )
 
  local output = ""
 
  for i, status in ipairs( statuses ) do
    if string.lower(status) == "married" or string.lower(status) == "remarried" then
      output = output .. CategoryLink( "Married Characters", vars.Pagename, status )
    else
      output = output .. CategoryLink( status .. " Characters", vars.Pagename, status )
    end
  end
 
  output = output .. " " .. field.Value2
 
  return output
end
 
function CharacterInfobox.Occupation( field, vars )
  local occupations = require('Module:CharacterInfoboxOccupations')
  local output = field.Value
 
  for key, value in pairs(occupations) do
    if string.find( string.lower(field.Value), key ) ~= nil then
      for i, category in ipairs( value ) do
        output = output .. CategoryLink( category, vars.Pagename, "" )
      end
    end
  end
 
  return output
end
 
function CharacterInfobox.Gender( field, vars )
  local output = ""
  local genderExploded = HF.explode( ";", field.Value )
 
  for i, gender in ipairs( genderExploded ) do
    local category = gender .. " Characters"
    output = output .. CategoryLink( category, vars.Pagename, gender ) .. ", "
  end
 
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 ) -- Remove last comma and space
  end
 
  return output .. " " .. field.Value2
end
 
function CharacterInfobox.Height( field, vars )
  local output    = ""
  local valid     = false -- to check if the height (in ft.) is in a valid format
  local validInch = false -- to check if the height (in inches) is in a valid format
  local delimiter = ""
 
    if string.find( field.Value, "'" ) ~= nil then
      valid     = true
      delimiter = "'"
    elseif string.find( field.Value, "ft" ) ~= nil then
      valid     = true
      delimiter = "ft"
    end
 
    if valid == true then
      local heightExploded = HF.explode( delimiter, field.Value )
 
      local feet           = string.match( tostring( heightExploded[1] ), "%d+" )
      local inches         = string.match( tostring( heightExploded[2] ), "%d+" )
 
      if type( feet ) == nil then
        feet = "0"
      end
      if type( inches ) == nil then
        inches = "0"
      end
 
 
      local heightValid    = feet .. "\' " .. inches .. "\""
      local feetPadded     = AddZeros( feet, 5 )
      local inchesPadded   = AddZeros( inches, 2 )
      local heightPadded   = feetPadded .. "\' " .. inchesPadded .. "\""
 
      local footCategory    = "Height " .. feet .. "'"
      local inchesCategory  = "Height " .. heightValid
 
      local from           = mw.uri.encode( "%20" .. feetPadded .. "'" .. inchesPadded .. "\"", "PATH" )
      local category       = tostring( mw.uri.canonicalUrl( ":Category:Height", "from=" .. from ) )
 
      -- Link to Height Category with from= parameter
      output = ExternalLink( category, heightValid, true )
 
      -- All into Height Category, sorted by Height and then Pagename
      output = output .. CategoryLink( "Height", heightPadded .. vars.Pagename, "" )
 
      -- All of the same 'Feet' into appropriate Foot category, sorted by inches then pagename.
      output = output .. CategoryLink( footCategory, inchesPadded .. vars.Pagename, "" )
 
      -- All of the same inches in the same feet category, sorted by pagename.
      output = output .. CategoryLink( inchesCategory, vars.Pagename, "" )
 
      -- Concat Height2
      output = output .. " " .. field.Value2
 
    else
      output = field.Value .. " " .. field.Value2
    end
 
  return output
end
 
function CharacterInfobox.Weight( field, vars )
  local output = ""
  local Units  = require('Module:Units')
  local unit   = ""
 
  if string.find( field.Value, "lbs" ) then
    unit = "lbs"
  elseif string.find( field.Value, "kg" ) then
    unit = "kg"
  elseif string.find( field.Value, "ton" ) then
    unit = "ton"
  else
    unit = ""
  end
 
  if unit ~= "" then
    local weight    = tonumber( string.match( field.Value, "%d+" ) )
    local weightLbs = HF.round( weight * Units[unit].lbs , 0 )
    local weightKg  = HF.round( weight * Units[unit].kg , 0 )
 
    local weightValid = weightLbs .. " lbs (" .. weightKg .. " kg)"
 
    local subcategory      = WeightSubcategory( weightLbs )
 
    local parameter = "from="
 
    if subcategory == 0 then
      parameter   = "until="
      subcategory = 100
    end
 
    local category    = tostring( mw.uri.canonicalUrl( ":Category:Weight", parameter .. AddZeros( subcategory, 5 ) ) )
 
    output = ExternalLink( category, weightValid, true )
 
    output = output .. CategoryLink( "Weight", "Weight " .. weightLbs, "" )
 
    output = output .. " " .. field.Value2
  else
    output = field.Value .. " " .. field.Value2
  end
 
  return output
end
 
function CharacterInfobox.Eyes( field, vars )
  local output = ""
  local eyes_table = HF.explode( ",", field.Value )
 
  for i, eyes in ipairs(eyes_table) do
    output = output .. EyesCategory( eyes, vars ) .. ", "
  end
 
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 ) -- Remove last comma and space
  end
 
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
 
  return output
end
 
function CharacterInfobox.Hair( field, vars )
  local output = ""
  local hair_table = HF.explode( ",", field.Value )
 
  for i, hair in ipairs(hair_table) do
    output = output .. HairCategory( hair, vars ) .. ", "
  end
 
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 ) -- Remove last comma and space
  end
 
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
 
  return output
end
 
function CharacterInfobox.Skin( field, vars )
  local output = ""
  local skin = HF.firstToUpper( field.Value )
    if string.lower( skin ) == "none" or string.lower( skin ) == "n/a" then
      output = output .. CategoryLink( "No Skin", vars.Pagename, "No Skin" )
    else
      output = output .. CategoryLink( skin .. " Skin", vars.Pagename, skin )
    end
 
    output = output .. " " .. field.Value2
  return output
end
 
function CharacterInfobox.UnusualFeatures( field, vars )
  local output = field.Value  
 
  -- Add categorising links
 
  local unusualFeatures = require('Module:CharacterInfoboxUnusualFeatures')
  local valid = unusualFeatures.valid
  local exceptions = unusualFeatures.exceptions
 
  output = output .. CategoriesFromKeywords( field.Value, valid, exceptions, vars )
 
  return output
end
 
function CharacterInfobox.Origin( field, vars )
  local output = field.Value  
 
  local origins = require('Module:CharacterInfoboxOrigins')
 
 
  for key, value in pairs(origins) do
    if string.find( string.lower(field.Value), key ) ~= nil then
      for i, category in ipairs( value ) do
        output = output .. CategoryLink( category, vars.Pagename, "" )
      end
    end
  end
 
  return output
end
 
function CharacterInfobox.Universe( field, vars )
  local output = ""
 
  if string.find( field.Value, ";" ) == nil then
    output = output .. UniverseCategory( field.Value, vars )
  else
    local universes = HF.explode( ";", field.Value )
 
    for i, universe in ipairs( universes ) do
      output = output .. UniverseCategory( universe, vars ) .. ", "
    end
  end
 
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 ) -- Remove last comma and space
  end
 
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
 
  if not HF.isempty( field.ValueRef ) then
    output = output .. " " .. field.ValueRef
  end
 
  return output
end
 
function CharacterInfobox.Sector( field, vars )
  local output = Link( "Sector " .. field.Value, field.Value )
  if string.find( vars.Theme, "greenlantern" ) ~= nil then
    output = output .. CategoryLink( "Green Lantern Corps member", vars.Pagename, "" )
  end
  return output
end
 
function CharacterInfobox.Ctry( field, vars )
  local substitutes = require('Module:CharacterInfoboxCtry')
  local output = ""
 
  if string.find( field.Value, "%[%[.+%]%]" ) == nil then
    if type( substitutes[field.Value] ) == "string" then
      output = Link( substitutes[field.Value] )
    else
      output = Link( field.Value )
    end
  else
    output = field.Value
  end
 
  return output
end
 
function CharacterInfobox.Creators( field, vars )
local output = ""
  local SC = require('Module:StaffCorrection')
 
  local delimiter = ";"
 
  local creators = HF.explode( delimiter, field.Value )
 
  for i, creator in ipairs( creators ) do
   if type( creator ) ~= nil then
    creator = SC.Correction( creator )
    output = output .. CategoryLink( creator .. "/Creator", vars.Pagename, "" )
    output = output .. Link( creator, creator ) .. ", "
    else 
    output = output .. CategoryLink ("Character Creators Needed", vars.Pagename, "" )
  end
 end
  if string.sub( output, -2, -1 ) == ", " then
    output = string.sub( output, 1, -3 ) -- Remove last comma and space
  end
 
  if string.sub( output, -1, -1 ) == "," then
    output = string.sub( output, 1, -2 ) -- Remove last comma
  end
 
  if not HF.isempty( field.Value2 ) then
    output = output .. " " .. field.Value2
  end
return output
end
 
function CharacterInfobox.OriginalPublisher( field, vars )
local output = field.Value
 
  if string.lower( field.Value ) ~= "dc" then
    output = output .. CategoryLink( field.Value .. " Characters", vars.Pagename, "" )
  end
 
return output
end
 
return CharacterInfobox
Community content is available under CC-BY-SA unless otherwise noted.