119 lines
3.3 KiB
TypeScript

import { OutputResponse } from "./types";
import { Context, Output } from "./definitions";
export function getPerfectMatch(
config: Output,
outputs: OutputResponse[],
): OutputResponse | null {
return (
outputs.find(
({ make, model, serial }) =>
make === config.make &&
model === config.model &&
serial === config.serial,
) ?? null
);
}
export function getNamePreferences(
outputs: OutputResponse[],
config: Output,
): (OutputResponse | null)[] {
return Array.from(
{ length: config.names?.length ?? 0 },
(_, idx) =>
outputs.find(({ name }) => config.names?.[idx] === name) ?? null,
);
}
export enum OutputScore {
ID_MATCH = 3,
NAME_MATCH = 2,
WILDCARD_MATCH = 1,
NO_MATCH = 0,
}
export function computeGroupScore(
config: Output,
output: OutputResponse | OutputResponse[],
) {
if (getPerfectMatch(config, [output].flat())) {
return OutputScore.ID_MATCH;
}
const preferences = getNamePreferences([output].flat(), config);
if (preferences.some((preference) => preference !== null)) {
return OutputScore.NAME_MATCH;
}
if (config.names?.includes("*")) {
return OutputScore.WILDCARD_MATCH;
}
return OutputScore.NO_MATCH;
}
export function computeContextScore(
config: Context,
outputs: OutputResponse[],
): [score: number, outputMap: Map<string, OutputResponse> | undefined] {
let score = 0;
const map = new Map<string, OutputResponse>();
const outputSet = new Set(outputs);
const usedGroups = new Set<Output>();
Object.values(config.outputs).forEach((output) => {
const match = getPerfectMatch(output, Array.from(outputSet));
if (match === null || output.group === undefined) {
return;
}
console.log(
`ID_MATCH for group "${output.group}" on output "${match.name}"`,
);
score += OutputScore.ID_MATCH;
outputSet.delete(match);
usedGroups.add(output);
map.set(output.group, match);
});
let groups = config.outputs.filter((group) => !usedGroups.has(group));
if (groups.length === 0) return [score, map] as const;
outputs = Array.from(outputSet);
const preferences = groups.map(getNamePreferences.bind(null, outputs));
const maxPreferences = Math.max(...preferences.map(({ length }) => length));
Array.from({ length: maxPreferences }, (_, idx) =>
preferences.forEach((preference, jdx) => {
if (
idx < preference.length &&
preference[idx] !== null &&
outputSet.has(preference[idx]) &&
groups[jdx].group !== undefined
) {
console.log(
`NAME_MATCH for group "${groups[jdx].group}" on output "${preference[idx].name}"`,
);
score += OutputScore.NAME_MATCH;
outputSet.delete(preference[idx]);
usedGroups.add(groups[jdx]);
map.set(groups[jdx].group, preference[idx]);
}
}),
);
groups = groups.filter((group) => !usedGroups.has(group));
if (groups.length > 1) {
return [0, undefined];
} else if (groups.length === 0) {
return [score, map];
} else if (groups[0].group !== undefined && groups[0].names?.includes("*")) {
map.set(groups[0].group, Array.from(outputSet)[0]);
console.log(
`WILDCARD_MATCH for group "${groups[0].group}" on output "${map.get(groups[0].group)}"`,
);
return [score + OutputScore.WILDCARD_MATCH, map];
} else {
return [0, undefined];
}
}