119 lines
3.3 KiB
TypeScript
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];
|
|
}
|
|
}
|