-- 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 picked, withMarker, withoutMarker = {}, {}, {} for _, building in ipairs(buildings or {}) do if chosen ~= nil and chosen[building.id] then table.insert(picked, building) elseif building.hasMarker then table.insert(withMarker, building) elseif showAll then table.insert(withoutMarker, building) end end local rows = {} for _, list in ipairs({sortedBy(picked, "name"), sortedBy(withMarker, "name"), sortedBy(withoutMarker, "name")}) do for _, building in ipairs(list) do table.insert(rows, building) end end return rows end