-- AD Flow View -- Rene regler for Flows-fanens oprydning (ingen spil-API): tavlens grupper og rækkefølge, hvilke -- traktorer og bygninger der vises som standard, og hvad "Vis alle" tilføjer. ADFlowView = {} -- Naturlig sortering: tal i navne sammenlignes som tal ("Biogas 9" < "Biogas 10"). local function naturalKey(text) local parts = {} local value = string.lower(tostring(text or "")) local position = 1 while position <= #value do local digits = string.match(value, "^%d+", position) if digits ~= nil then table.insert(parts, {number = tonumber(digits)}) position = position + #digits else local chunk = string.match(value, "^%D+", position) table.insert(parts, {text = chunk}) position = position + #chunk end end return parts end function ADFlowView.naturalLess(a, b) local ka, kb = naturalKey(a), naturalKey(b) for index = 1, math.max(#ka, #kb) do local pa, pb = ka[index], kb[index] if pa == nil then return true end if pb == nil then return false end if pa.number ~= nil and pb.number ~= nil then if pa.number ~= pb.number then return pa.number < pb.number end elseif pa.number ~= nil or pb.number ~= nil then return pa.number ~= nil elseif pa.text ~= pb.text then return pa.text < pb.text end end return false end local function sortedBy(list, field) local copy = {} for _, item in ipairs(list or {}) do table.insert(copy, item) end table.sort(copy, function(a, b) if a[field] ~= b[field] then return ADFlowView.naturalLess(a[field], b[field]) end return tostring(a.id) < tostring(b.id) end) return copy end -- Tavlen: forsyning ("Ind til bygning") først, så udkørsel ("Ud fra bygning"); hver gruppe efter navn. -- {{kind, runs}, ...}; tomme grupper udelades. function ADFlowView.boardGroups(runs) local byKind = {supply = {}, outbound = {}} for _, run in ipairs(runs or {}) do table.insert(byKind[run.kind == "outbound" and "outbound" or "supply"], run) end local groups = {} for _, kind in ipairs({"supply", "outbound"}) do if #byKind[kind] > 0 then table.insert(groups, {kind = kind, runs = sortedBy(byKind[kind], "name")}) end end return groups end -- Samme rækkefølge som tavlen, som én liste (flow-vælgeren). function ADFlowView.orderedRuns(runs) local result = {} for _, group in ipairs(ADFlowView.boardGroups(runs)) do for _, run in ipairs(group.runs) do table.insert(result, run) end end return result end -- Traktorer: vehicles = {{id, label, state = "in"|"free"|"other"|"blocked"}}. Standard: flowets egne, -- så ledige der kan bruges. showAll tilføjer traktorer i andre flows og låste (vogn passer ikke). local STATE_ORDER = {"in", "free", "other", "blocked"} function ADFlowView.vehicleRows(vehicles, showAll) local byState = {} for _, entry in ipairs(vehicles or {}) do byState[entry.state] = byState[entry.state] or {} table.insert(byState[entry.state], entry) end local rows = {} for _, state in ipairs(STATE_ORDER) do if showAll or state == "in" or state == "free" then for _, entry in ipairs(sortedBy(byState[state], "label")) do table.insert(rows, entry) end end end return rows end function ADFlowView.hiddenCount(all, shown) return #(all or {}) - #(shown or {}) end -- Bygninger: buildings = {{id, name, hasMarker}}, chosen = {[id] = true}. Valgte først; bygninger uden -- markør kun hvis valgte eller showAll (de kan alligevel ikke bruges før en markør er sat). function ADFlowView.buildingRows(buildings, chosen, showAll) local shown, withoutMarker = {}, {} for _, building in ipairs(buildings or {}) do if (chosen ~= nil and chosen[building.id]) or building.hasMarker then table.insert(shown, building) elseif showAll then table.insert(withoutMarker, building) end end -- fast rækkefølge: bygningsnavn, så markørnavn (label) — et tryk må ikke flytte rækken under markøren local function byNameThenLabel(list) local copy = {} for _, item in ipairs(list) do table.insert(copy, item) end table.sort(copy, function(a, b) if a.name ~= b.name then return ADFlowView.naturalLess(a.name, b.name) end if (a.label or "") ~= (b.label or "") then return ADFlowView.naturalLess(a.label or "", b.label or "") end return tostring(a.id) < tostring(b.id) end) return copy end local rows = {} for _, list in ipairs({byNameThenLabel(shown), byNameThenLabel(withoutMarker)}) do for _, building in ipairs(list) do table.insert(rows, building) end end return rows end -- "Chicken Coop x3 + Cow Barn": ens navne slås sammen med antal, i rækkefølge efter første forekomst. function ADFlowView.joinCounted(names, separator, empty) local order, counts = {}, {} for _, name in ipairs(names or {}) do local key = tostring(name) if counts[key] == nil then counts[key] = 0 table.insert(order, key) end counts[key] = counts[key] + 1 end if #order == 0 then return empty end local parts = {} for _, key in ipairs(order) do table.insert(parts, counts[key] > 1 and string.format("%s x%d", key, counts[key]) or key) end return table.concat(parts, separator) end