Jump to content

Module:Sandbox/RedWolf

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by RedWolf (talk | contribs) at 22:55, 27 January 2025 (titled coords). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
local p = {}
--local wd = require('Module:Wd')
local titled_coords = require('Module:Titled_coords')

-- Information about a mountain from Module arguments and Wikidata.
local Mountain = { rank, page, name, eid, elevation, elevation_wd,
                   prominence , range, fa, coords, notes }

-- Runtime options about what information to display
local Options  = { showFA = false, showCoord = false, showTCoord = false,
                   showNotes = false, showRank = false, showRange = false}

-- Wikidata properties
local WD_PROPERTIES = {
    elevation  = "P2044",
    prominence = "P2660",
    mtn_range  = "P4552",
    coords     = "P625",
    sig_event  = "P793",
    pt_in_time = "P585"
}
local QID_FIRST_ASCENT = "Q1194369"

local errors

-- Split a string based on a separator
local function split(istring, sep)
    -- if sep is null, set it as comma
    if sep == nil then sep = ',' end

    local t = {}
    for str in string.gmatch(istring, '([^'..sep..']+)') 
    do
        table.insert(t, str)
    end
    return t
end

-- Extract raw elevation/prominence value
local function extractRaw(value)
    local i, i1, i2, n

    if value == nil then return -1 end
    i = string.find(value, " metre")
    if i then
        n = string.sub(value, 1, i-1):gsub(',', '')
    else
        n = -1
    end
    return n
end

-- Call {{elevation_cells} to format the values
local function getElevationCells(frame, elev, unit) --23
    if frame.expandTemplate then
        return frame:expandTemplate{title='elevation_cells', args= { elev, unit}}
    end

    return "{{elevation_cells|" .. elev .. "|" .. unit .. "}}"
end

local function getPage(name)
    local parts = split(name,"|")
    local page = parts[1]
    local n = string.find(page, "%[%[")
    if n then
        page = string.sub(page,3)
    end
    n = string.find(page, "%]%]")
    if n then
        page = string.sub(page,1,n-1)
    end
    return page
end

local function getWD(frame, eid, name, flag)
    if not frame.preprocess then
        return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
    end

    local args = "property|"
    if flag then args = args .. flag .. "|" end
    args = args .. name .. "|eid=" .. eid 
    local invoke = "{{#invoke:Wd|" .. args .. "}}"
    local value = frame:preprocess(invoke)
    mw.log(invoke .. " => " .. value)
    return value
end

local function getWD(frame, eid, name)
    return getWD(frame, eid, name, nil)
end

local function getWDLinked(frame, eid, name)
    return getWD(frame, eid, name, "linked")
end

local function getWDRaw(frame, eid, name)
    return getWD(frame, eid, name, "raw")
end

-- Get an entity's property from Wikidata
local function getWDProperty(frame, eid, name, linked)
    mw.log("eid=" .. eid .. " name=" .. name)
--[[    local stmts = mw.wikibase.getBestStatements(eid, name)
    if stmts ~= nil then
        mw.logObject(stmts)
        for i=1,#stmts do
            mw.log("stmts["..i.."]="..stmts[i]);
        end
    end ]]

    if frame.preprocess then
        local args = "property|"
        if linked then args = args .. "linked|" end
        args = args .. name .. "|eid=" .. eid 
        local invoke = "{{#invoke:Wd|" .. args .. "}}"
        local value = frame:preprocess(invoke)
        mw.log(invoke .. " => " .. value)
        return value
    end
    return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
end
--    if frame.expandTemplate then
--        local args = { ['1'] = name, ['page'] = page }
--        return wd._property({eid, args})
--        local args = { ['1'] = 'property', ['2'] = name, ['page'] = page }
--        return frame:expandTemplate{title='Wikidata', args= args}

local function getCoords(frame, eid)
    return getWD(frame, eid, WD_PROPERTIES.coords, nil)
end

local function getTitledCoords(frame, eid, title)
    local raw_coords = getWDRaw(frame, eid, WD_PROPERTIES.coords)
    local invoke = "{{#invoke:Titled_coords|main|" .. raw_coords .. "|" .. title .. "}}"
    --local fmt_coords = frame:preprocess(invoke)
    mw.log(invoke .. " => " .. fmt_coords)
    return "????"
    --return fmt_coords
end

local function getElevation(frame, eid)
    value = getWD(frame, eid, WD_PROPERTIES.elevation)
    return extractRaw(value)
end

local function getFirstAscent(frame, eid)
    if frame.preprocess == nil then return "????" end

    local names = WD_PROPERTIES.sig_event .. "|" .. QID_FIRST_ASCENT .. "|" .. WD_PROPERTIES.pt_in_time
    local value = frame:preprocess("{{#invoke:Wd|property|qualifier|" .. names .. "|eid=" .. eid .. "}}")
    mw.log("FA value = " .. value)
    if value == "" then
        mw.log("No FA found for eid=" .. eid)
        return " "
    end

    -- Find date such as: 10 July 1913
    local i1, i2 = string.find(value, "%(%d+%s%a*%s%d%d%d%d%)")
    if i1 then
        --mw.log("i1="..i1)
        local date = string.sub(value, i1+1, i2-1)
        mw.log("FA date = " .. date)
        local len  = string.len(date)
        local year = string.sub(date, len-4, len)
        return year
    end

    -- Find date with just the year; e.g. (2025)
    i1, i2 = string.find(value, "%(%d+%)")
    if i1 then
        local year = string.sub(value, i1+1, i2-1)
        return year
    end
    return "FA date format unknown"
end

-- get prominence from Wikidata
local function getProminence(frame, eid)
    local prom = getWD(frame, eid, WD_PROPERTIES.prominence, nil)
    return extractRaw(prom)
end

-- get mountain range from Wikidata
local function getRange(frame, eid)
    return getWDLinked(frame, eid, WD_PROPERTIES.mtn_range)
end

-- generate table header
local function header(options, unit)
    local unit_1, unit_2

    if unit == nil or unit == "" then
        unit = 'm'
    end

    if unit == 'm' then unit_1 = 'm'; unit_2 = 'ft'
    else unit_1 = 'ft'; unit_2 = 'm'
    end

    local s = '{| class="wikitable sortable"\n!'

    if options.showRank  then s = s .. " align=\"left\" rowspan=2|Rank||" end
    s = s .. "rowspan=2|Mountain/Peak ||colspan=2|Elevation ||colspan=2| Prominence "
    if options.showRange then s = s .. "||rowspan=2| Subrange" end
    if options.showFA    then s = s .. "||rowspan=2| FA "   end
    if options.showCoord then s = s .. "||rowspan=2| Coordinates" end
    if options.showNotes then s = s .. "||rowspan=2| Notes" end

    s = s .. "\n|-\n"
    s = s .. '!' .. unit_1 .. '||' .. unit_2 .. '||' .. unit_1 .. '||' .. unit_2 .. "\n"

    return s
end

local function finish()
    return "|}"
end

--[[ Process run options
     rank    - show ranking
     range   - show mountain range or subrange from WD
     fa      - show first ascent (year only) from WD
     coords  - show coordinates from WD
     tcoords - show titled coordinates from WD
     notes   - show notes
]]
local function processOptions(runOptions)
    local o = Options
    if runOptions == nil then return o end
    mw.log("runOptions=" .. runOptions)

    local parts = split(runOptions, ",")
    for i=1,#parts do
        option = parts[i]
        mw.log("option=" .. option)
        if option == "rank"    then o.showRank   = true end
        if option == "fa"      then o.showFA     = true end
        if option == "coords"  then o.showCoord  = true end
        if option == "tcoords" then o.showTCoord = true end
        if option == "range"   then o.showRange  = true end
        if option == "notes"   then o.showNotes  = true end
    end

    return o
end

local function processLine(frame, options, line)
    local parts, n
    local name, elev, page, notes

    -- argument contains elevation, page link and notes
    parts = split(line, ",")
    if #parts < 3 then
        local m = "<br/>Bad format on argument (<nowiki>" .. line .. "</nowiki>) -- skipped"
        errors = errors .. m
        mw.log(m)
        return nil
    end

    local mtn = Mountain

    elev = parts[1]
    name = parts[2]
    if name then
        page = getPage(name)
        mw.log("name = " .. name .. ";page = " .. page)
    else
        mw.log("name is null")
        return nil
    end

    mtn.name = name
    mtn.page = page
    mtn.elevation = elev;

    if options.showNotes then
        notes = parts[3]
        n = string.find(notes, "\n")
        if n then
            notes = string.sub(notes, 1, n-1)
        end
        mtn.notes = notes
    end

    local eid = mw.wikibase.getEntityIdForTitle(page)
    mw.log("page="..page .. ",eid=" .. eid)
    mtn.eid = eid

    mtn.elevation_wd = getElevation(frame, eid)
    mtn.prominence   = getProminence(frame, eid)

    if options.showRange then
        mtn.range = getRange(frame, eid)
    end

    if options.showFA then
        mtn.fa    = getFirstAscent(frame, eid)
    end

    if options.showCoord then
        mtn.coords = getCoords(frame, eid)
    end

    if options.showTCoord then
        mtn.coords = getTitledCoords(frame, eid, page)
    end

    return mtn
end

local function processRange(ranges, mtn)
    local found = false;
    local range = mtn.range
    for k,v in pairs(ranges) do
        if v == range then
            found = true; break
         end
    end

    if not found then
        mw.log("Adding range " .. range)
        table.insert(ranges, range)
    else
        local i1, i2 = string.find(range, "|")
        if i1 then
            name = string.sub(range, i1+1)
        else
            local len = string.len(range)
            name = string.sub(range, 3, len-2)
        end
        mtn.range = name
    end
end

function p.list(frame) -- 34
    local debug = false
    local rank_number = 0
    local last_elev = ""

    errors = ""
    local unit  = frame.args[1]
    local options = processOptions(frame.args[2])
    local output = header(options, unit)
    local ranges = {}

    for i=3,999,1 do
        line = frame.args[i]
        if line == nil then break end

        mw.log("line=" .. line)
        local mtn = processLine(frame, options, line)
        if mtn then
            if options.showRank and last_elev ~= mtn.elevation then
                rank_number = rank_number + 1
                mtn.rank = rank_number
                last_elev = mtn.elevation
            end

            if options.showRange then
                processRange(ranges, mtn)
            end

            elev_cells = getElevationCells(frame, mtn.elevation, unit)
            prom = mtn.prominence
            if prom ~= nil and prom ~= "-1" and prom ~= "" then
                prom_cells = getElevationCells(frame, prom, unit)
            else
                prom_cells = "&nbsp;||&nbsp;"
            end

            mw.log("elev=" .. mtn.elevation ..";elev_wd="..mtn.elevation_wd)
            if options.showNotes and mtn.elevation ~= mtn.elevation_wd then
                local mm = "<br/><font color=green>Local/WD elevations mismatch: " .. "\"" .. mtn.elevation .. "\"".. "/\"" .. mtn.elevation_wd.. "\"</font>"
                mtn.notes = mtn.notes .. mm
            end

            local s = "|-\n|"
            if options.showRank then s = s .. "align=center|" .. mtn.rank .. "||" end
            s = s .. mtn.name .. '\n|' .. elev_cells .. '\n|' .. prom_cells .. '\n|'
            if options.showRange then s = s .. '|' .. mtn.range  .. '\n' end
            if options.showFA    then s = s .. '|' .. mtn.fa     .. '\n' end
            if options.showCoord or options.showTCoord then s = s .. '|' .. mtn.coords .. '\n' end
            if options.showNotes then s = s .. '|' .. mtn.notes  .. '\n' end
            output = output .. s
         end
    end -- for

    output = output .. finish()
    if debug then
        output = "</br><nowiki>"..output.."</nowiki>".."\n"..output
    end
    if string.len(errors) > 0 then
        output = output .. "<font color=red>" .. errors .. "</font>"
    end
    return output
end

--[[
Test via Preview Window Debug console
  print(p.test())
]]
function p.test()
    local frame = mw.getCurrentFrame()
--    if frame then mw.logObject(frame) end
--    local frame = {}
    frame.args = {}
    frame.args[1] = 'm'
    frame.args[2] = "rank,range,fa,xcoords,xnotes"
    frame.args[3] = "3954,[[Mount Robson]],Highest point in the Canadian Rockies\n"
    frame.args[4] = "3747,[[Mount Columbia (Canada)|Mount Columbia]],Highest point in [[Alberta]]"
    frame.args[5] = "3246,[[Apex Mountain (Chaba Icefield)|Apex Mountain]],Named for its location in the centre of the Clemenceau Icefield"
    frame.args[6] = "3246,[[Mount Smythe (Alberta)|Mount Smythe]],Named for an English mountaineer"

    frame.args[7] = ""
    frame.args[8] = "&nbsp;"

    return p.list(frame)
end

function p.test2()
    local s = '<a href="/wiki/Rainbow_Range_(Rocky_Mountains)" title="Rainbow Range (Rocky Mountains)">Rainbow Range</a>'
    --local i1,i2 = string.find(s,"%>(.*)%<%/a%>")
    local i1,i2 = string.find(s,"%b><")
    if i1 then 
        mw.log("i1=" .. i1 .. " i2=" .. i2)
        mw.log(string.sub(s,i1+1,i2-1))
    else
        mw.log("not found")
    end
end

return p

--[[
{| class="wikitable sortable"
|- bgcolor="#ffffcc"
! align="left" rowspan=2|Rank||rowspan=2|Mountain/Peak  ||colspan=2|Elevation ||colspan=2| Prominence ||rowspan=2| Subrange
!rowspan=2| FA ||rowspan=2| Notes ||rowspan=2| References
|-
!m || ft || m || ft
|-
|align=center|1||Mount Robson
|{{elevation_cells|3,959|m}}|{{elevation_cells|2829|m}}||Rainbow Range
|1913||Highest point in the Canadian Rockies|| <ref name=robson/>
]]