Module:Chem box

From Space Station 14 Wiki
Revision as of 21:33, 24 October 2024 by UpAndLeaves (talk | contribs) (Surely this works first try right? (Mobile coding, bad code should fix))
Module documentation
View or edit this documentation (about module documentation)
Uses JSON data
This module uses JSON data pages:

Implements {{chem box}}.


local p = {} --p stands for package
local getArgs = require('Module:Arguments').getArgs
local yesNo = require('Module:Yesno')

local chem_data = mw.loadJsonData("Module:Chem box/chem data.json")

local current_frame = mw.getCurrentFrame()

local beaker_el = current_frame:expandTemplate {
    title = 'Beaker'
}

-- ====================


local function numeric_table_length(t)
    local count = 0
    for _ in ipairs(t) do count = count + 1 end
    return count
end

local function table_length(t)
    local count = 0
    for _ in pairs(t) do count = count + 1 end
    return count
end

local function table_has_value(tab, val)
    for _, value in ipairs(tab) do
        if value == val then
            return true
        end
    end

    return false
end

local function assert_value_not_nil(value, error_message)
    if value == nil then
        if error_message == nil then
            error("value is nil")
        else
            error(error_message)
        end
    end
end

-- Makes the first letter uppercase.
-- Source: https://stackoverflow.com/a/2421746
local function capitalize(str)
    return (str:gsub("^%l", string.upper))
end

local function passthrough_assert_true(value, valueToReturnIfTrue, errorMessageOnFalse)
    if value then
        return valueToReturnIfTrue
    else
        error(errorMessageOnFalse)
    end
end

local function find_first_numeric_table_item_matching_condition(table, condition)
    for i, item in ipairs(table) do
        if condition(item, i, table) then
            return item
        end
    end
end

-- table concat function because ofcourse fucking table.concat doesn't work
local function concat_numberic_table(tbl, sep)
    local temp_table = {}
    for i = 1, numeric_table_length(tbl) do
        table.insert(temp_table, tbl[i])
    end

    return table.concat(temp_table, sep)
end

local function ternary_strict(valueToCheck, valueIfTrue, valueIfFalse)
    if valueToCheck == true then
        return valueIfTrue
    else
        return valueIfFalse
    end
end

-- ====================

-- Lookups reagent by ID or name.
--
-- Raises an error if no reagent was found.
-- Set `no_error` to `true` to return `nil` instead.
function p.lookup_reagent(query, no_error)
    local query_lower = string.lower(query)

    for _, reagent in ipairs(chem_data) do
        assert_value_not_nil(reagent.id)
        assert_value_not_nil(reagent.name)

        if reagent.id == query then return reagent end
        if string.lower(reagent.name) == query_lower then return reagent end
    end

    return passthrough_assert_true(
        no_error,
        nil,
        "failed to lookup reagent: no match was found"
    )
end

-- ====================

function p.generate_chem_box(frame)
    local args = getArgs(frame)

    local query = args[1]
    assert_value_not_nil(query, "failed to generate chem box: query was not provided")

    -- ===================

    local reagent = p.lookup_reagent(query)
    assert_value_not_nil(reagent.color)
    assert_value_not_nil(reagent.name)
    assert_value_not_nil(reagent.recipes) 
    assert_value_not_nil(reagent.effects)
    assert_value_not_nil(reagent.desc)
    assert_value_not_nil(reagent.physicalDesc)
    assert_value_not_nil(reagent.textColorTheme)

    local recipes_container_el = mw.html.create("div")
    if numeric_table_length(reagent.recipes) == 0 then
        local no_recipes_text_el = mw.html.create("span")
            :css("color", "gray")
            :node("No recipes")

        recipes_container_el:node(no_recipes_text_el)
    else
        for _, recipe in ipairs(reagent.recipes) do
            assert_value_not_nil(recipe.id)
            assert_value_not_nil(recipe.reactants)
            assert_value_not_nil(recipe.products)

            local recipe_box_template_args = {}
            recipe_box_template_args.name = recipe.id

            -- a list of catalist reactants.
            -- contains "id" and "amount"
            local catalyst_reactants = {}

            for reactant_i, reactant in ipairs(recipe.reactants) do
                local reactant_id = reactant[1]
                local reactant_amount = reactant[2]
                local reactant_is_catalyst = reactant[3] or false

                local label = reactant_id

                if reactant_is_catalyst then
                    table.insert(catalyst_reactants, {
                        id = reactant_id,
                        amount = reactant_amount
                    })
                end

                local component_el = current_frame:expandTemplate {
                    title = 'Recipe Component',
                    args = {
                        item = label,
                        amount = reactant_amount
                        -- TODO
                        -- image = ""
                    }
                }

                recipe_box_template_args['component-' .. reactant_i] = component_el
            end

            recipe_box_template_args.transformer = beaker_el

            for product_i, product in ipairs(recipe.products) do
                local component_el = current_frame:expandTemplate {
                    title = 'Recipe Component',
                    args = {
                        item = product[1],
                        amount = product[2]
                        -- TODO
                        -- image = ""
                    }
                }

                recipe_box_template_args['result-' .. product_i] = component_el
            end

            -- add catalysts as products, if any
            for catalyst_product_i, catalyst_product_entry in ipairs(catalyst_reactants) do
                local product_id = catalyst_product_entry.id
                local product_amount = catalyst_product_entry.amount

                local label = current_frame:expandTemplate {
                    title = 'Tooltip',
                    args = {
                        '<sup class="quickbox-catalyst-note">+</sup>',
                        '<span class="quickbox-catalyst-note-tooltip">This product is a catalyst reactant, remaining after the reaction.</span>'
                    }
                } .. product_id

                local component_el = current_frame:expandTemplate {
                    title = 'Recipe Component',
                    args = {
                        item = label,
                        amount = product_amount
                        -- TODO
                        -- image = ""
                    }
                }

                local index = numeric_table_length(recipe.products) + catalyst_product_i
                recipe_box_template_args['result-' .. index] = component_el
            end

            local recipes_el = current_frame:expandTemplate {
                title = 'Recipe Box',
                args = recipe_box_template_args
            }

            recipes_container_el:node(recipes_el)
        end
    end

    local effects = concat_numberic_table(reagent.effects, "")

    local text_color = ternary_strict(
        reagent.textColorTheme == 'light',
        'var(--quickbox-header-text-theme-light)',
        'var(--quickbox-header-text-theme-dark)'
    )

    return current_frame:expandTemplate {
        title = 'Manual Chem Box',
        args = {
        	id = reagent.id,
            color = reagent.color,
            textcolor = text_color,
            name = capitalize(reagent.name),
            recipes = tostring(recipes_container_el:allDone()),
            metabolisms = effects,
            desc = reagent.desc,
            physicalDesc = reagent.physicalDesc,
        }
    }
end

function p.generate_chem_boxes_for_all_reagents()
    local container_el = mw.html.create("div")
        :addClass("reagents-list")

    for _, reagent in ipairs(chem_data) do
        assert_value_not_nil(reagent.id)

        container_el:node(
            p.generate_chem_box {
                reagent.id
            }
        )
    end

    return container_el:allDone()
end

function p.generate_chem_boxes_for_group(frame)
    local args = getArgs(frame)
    local query = args[1]
    assert_value_not_nil(query)
    query = string.lower(query)
    local container_el = mw.html.create("div")
        :addClass("reagents-list")

    for _, reagent in ipairs(chem_data) do
        assert_value_not_nil(reagent.id)
        assert_value_not_nil(reagent.group)
        if string.lower(reagent.group) == query then
            container_el:node(
                p.generate_chem_box {
                   reagent.id
               }
           )
        end
    end

    return container_el:allDone()
end

return p