Module:ElectoralCalendarMap

From Elections Wiki
Jump to navigation Jump to search

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

local p = {}

function p.load(frame)
    -- i understand chocolateman now, we can't fetch data from an outside source due to mediawiki's stupid restrictions
    local dataPage = "Data:Election_Data.json"
    local dataTitle = mw.title.new(dataPage)

    if not dataTitle then
        return "could not find data page '" .. dataPage .. "'!"
    end

    local dataContent = dataTitle:getContent()
    if not dataContent then
        return "could not retrieve content from '" .. dataPage .. "'!"
    end

    local APIData = mw.text.jsonDecode(dataContent)
    if not APIData then
        return "invalid JSON content in '" .. dataPage .. "'!"
    end

    local electionColors = {
        General = "#4682b4", -- blue
        Local = "#8a2be2", -- purple
        Statewide = "#008000", -- green
        Referendum = "#ffa500" -- orange
    }

    local currentDate = os.date("!%Y-%m-%dT%H:%M:%S")
    
    local function isUpcoming(electionDate)
        local formattedElectionDate = mw.ustring.gsub(electionDate, "[-:T]", ""):sub(1, 14)
        local formattedCurrentDate = mw.ustring.gsub(currentDate, "[-:T]", ""):sub(1, 14)
        return formattedElectionDate > formattedCurrentDate
    end

    local upcomingElections = {}
    for region, elections in pairs(APIData) do
        for _, election in ipairs(elections) do
            if isUpcoming(election.date) then
                table.insert(upcomingElections, {
                    region = region,
                    election = election
                })
            end
        end
    end

    table.sort(upcomingElections, function(a, b)
        return a.election.date < b.election.date
    end)

    local limitedElections = {}
    for i = 1, math.min(7, #upcomingElections) do
        table.insert(limitedElections, upcomingElections[i])
    end

    local combinedJSON = {}
    for _, entry in ipairs(limitedElections) do
        local region = entry.region
        local election = entry.election
        local mapDataTitle = mw.title.new("MapData:" .. region .. ".map")

        if mapDataTitle then
            local content = mapDataTitle:getContent()
            if content then
                local parsedContent = mw.text.jsonDecode(content)
                if parsedContent and type(parsedContent.features) == "table" then
                    for _, feature in ipairs(parsedContent.features) do
                        feature.properties.title = string.gsub(region, "_", " ")
                        feature.properties.description = string.format(
                            "<b>%s</b><br>%s<br>%s",
                            election.election_name,
                            election.date,
                            election.description
                        )

                        local fillColor = electionColors[election.election_type] or "#404040"
                        feature.properties.fill = fillColor
                        feature.properties["fill-opacity"] = 0.8

                        table.insert(combinedJSON, feature)
                    end
                else
                    mw.log("invalid or missing features in mapdata for region '" .. region .. "'!")
                end
            else
                mw.log("warning: couldn't fetch mapdata for region '" .. region .. "'!")
            end
        else
            mw.log("warning: couldn't create title object for region '" .. region .. "'!")
        end
    end

    local combinedMapData = mw.text.jsonEncode({
        type = "FeatureCollection",
        features = combinedJSON
    })

    local mapFrame = '<mapframe width="100%" height="400" zoom="3" longitude="0" latitude="0">' .. combinedMapData .. '</mapframe>'
    return frame:preprocess(mapFrame)
end

return p