tods-competition-factory 1.7.19 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3682,7 +3682,6 @@ const membershipMap = {
3682
3682
  function getParticipantMap({
3683
3683
  withIndividualParticipants,
3684
3684
  convertExtensions,
3685
- policyDefinitions,
3686
3685
  tournamentRecord,
3687
3686
  withSignInStatus,
3688
3687
  withScaleValues,
@@ -3690,32 +3689,23 @@ function getParticipantMap({
3690
3689
  withISO2,
3691
3690
  withIOC
3692
3691
  }) {
3693
- const participantAttributes = policyDefinitions?.[POLICY_TYPE_PARTICIPANT];
3694
- const filterAttributes = participantAttributes?.participant;
3695
3692
  const participantMap = {};
3696
- for (const participant of tournamentRecord.participants || []) {
3693
+ for (const participant of tournamentRecord.participants ?? []) {
3697
3694
  const participantId = participant?.participantId;
3698
3695
  participantId && initializeParticipantId({ participantMap, participantId });
3699
3696
  }
3700
- for (const participant of tournamentRecord.participants || []) {
3697
+ for (const participant of tournamentRecord.participants ?? []) {
3701
3698
  const participantCopy = makeDeepCopy(
3702
3699
  participant,
3703
3700
  convertExtensions,
3704
3701
  internalUse
3705
3702
  );
3706
- const filteredParticipant = filterAttributes ? attributeFilter({
3707
- template: participantAttributes.participant,
3708
- source: participantCopy
3709
- }) : participantCopy;
3710
- const { participantId, individualParticipantIds, participantType } = filteredParticipant;
3711
- Object.assign(
3712
- participantMap[participantId].participant,
3713
- filteredParticipant
3714
- );
3703
+ const { participantId, individualParticipantIds, participantType } = participantCopy;
3704
+ Object.assign(participantMap[participantId].participant, participantCopy);
3715
3705
  if (individualParticipantIds) {
3716
3706
  processIndividualParticipantIds({
3717
3707
  individualParticipantIds,
3718
- filteredParticipant,
3708
+ participantCopy,
3719
3709
  participantMap,
3720
3710
  participantType,
3721
3711
  participantId
@@ -3766,7 +3756,7 @@ function addIndividualParticipants({ participantMap }) {
3766
3756
  }
3767
3757
  function processIndividualParticipantIds({
3768
3758
  individualParticipantIds,
3769
- filteredParticipant,
3759
+ participantCopy,
3770
3760
  participantMap,
3771
3761
  participantType,
3772
3762
  participantId
@@ -3781,7 +3771,7 @@ function processIndividualParticipantIds({
3781
3771
  participantName,
3782
3772
  participantId: participantId2,
3783
3773
  teamId
3784
- } = filteredParticipant;
3774
+ } = participantCopy;
3785
3775
  const membership = membershipMap[participantType];
3786
3776
  individualParticipant[membership].push({
3787
3777
  participantRoleResponsibilities,
@@ -3844,7 +3834,6 @@ function initializeParticipantId({ participantMap, participantId }) {
3844
3834
  function hydrateParticipants({
3845
3835
  participantsProfile,
3846
3836
  useParticipantMap,
3847
- policyDefinitions,
3848
3837
  tournamentRecord,
3849
3838
  contextProfile,
3850
3839
  inContext
@@ -3853,7 +3842,6 @@ function hydrateParticipants({
3853
3842
  const participantMap = getParticipantMap({
3854
3843
  ...participantsProfile,
3855
3844
  ...contextProfile,
3856
- policyDefinitions,
3857
3845
  tournamentRecord
3858
3846
  })?.participantMap;
3859
3847
  return { participantMap };
@@ -9222,7 +9210,9 @@ const POLICY_MATCHUP_ACTIONS_DEFAULT = {
9222
9210
  },
9223
9211
  processCodes: {
9224
9212
  substitution: ["RANKING.IGNORE", "RATING.IGNORE"]
9225
- }
9213
+ },
9214
+ substituteAfterCompleted: false,
9215
+ substituteWithoutScore: false
9226
9216
  }
9227
9217
  };
9228
9218
 
@@ -11213,649 +11203,1127 @@ function getMatchUpDependencies(params) {
11213
11203
  };
11214
11204
  }
11215
11205
 
11216
- function getInitialRoundNumber({
11217
- drawPosition,
11218
- matchUps = []
11219
- }) {
11220
- const initialRoundNumber = matchUps.filter(
11221
- ({ drawPositions }) => drawPosition && drawPositions?.includes(drawPosition)
11222
- ).map(({ roundNumber }) => roundNumber).sort(numericSort)[0];
11223
- return { initialRoundNumber };
11224
- }
11225
-
11226
- function getContainedStructures({
11227
- tournamentRecord,
11228
- drawDefinition,
11229
- event
11230
- }) {
11231
- const events = tournamentRecord?.events || event && [event];
11232
- const drawDefinitions = events?.map((event2) => event2?.drawDefinitions).flat().filter(Boolean) || drawDefinition && [drawDefinition] || [];
11233
- const containedStructures = {};
11234
- const containerStructures = {};
11235
- const structureContainers = drawDefinitions.map((dd) => dd?.structures?.filter((structure) => structure?.structures)).flat().filter(Boolean);
11236
- for (const structureContainer of structureContainers) {
11237
- const { structures, structureId } = structureContainer || {};
11238
- structures && structureId && (containedStructures[structureId] = structures?.map(
11239
- (structure) => structure.structureId
11240
- )) && structures.forEach(
11241
- (structure) => containerStructures[structure.structureId] = structureContainer?.structureId
11242
- );
11206
+ function getEventPublishStatuses({ event }) {
11207
+ const itemType = `${PUBLISH}.${STATUS$1}`;
11208
+ const { timeItem } = getTimeItem({
11209
+ element: event,
11210
+ itemType
11211
+ });
11212
+ if (timeItem?.itemValue?.PUBLIC) {
11213
+ const { drawIds: publishedDrawIds = [], seeding } = timeItem.itemValue.PUBLIC || {};
11214
+ const publishedSeeding = {
11215
+ published: void 0,
11216
+ // seeding can be present for all entries in an event when no flights have been defined
11217
+ seedingScaleNames: [],
11218
+ drawIds: []
11219
+ // seeding can be specific to drawIds
11220
+ };
11221
+ if (seeding) {
11222
+ Object.assign(publishedSeeding, timeItem.itemValue.PUBLIC.seeding);
11223
+ }
11224
+ return {
11225
+ publishedDrawIds,
11226
+ publishedSeeding
11227
+ };
11243
11228
  }
11244
- return { containedStructures, containerStructures };
11229
+ return void 0;
11245
11230
  }
11246
11231
 
11247
- function isActiveMatchUp({
11248
- matchUpStatus,
11249
- winningSide,
11250
- tieMatchUps,
11251
- sides,
11252
- score
11232
+ function getEventSeedAssignments({
11233
+ publishedSeeding,
11234
+ usePublishState,
11235
+ withSeeding,
11236
+ participant,
11237
+ event
11253
11238
  }) {
11254
- const participantAssigned = sides?.find(({ participantId }) => participantId);
11255
- const activeTieMatchUps = tieMatchUps?.filter(isActiveMatchUp)?.length;
11256
- const scoreExists = scoreHasValue({ score });
11257
- return scoreExists || activeTieMatchUps || winningSide && participantAssigned || // if winningSide and no participant assigned => "produced" WALKOVER
11258
- // must exclude IN_PROGRESS as this is automatically set by updateTieMatchUpScore
11259
- // must exclude WALKOVER and DEFAULTED as "produced" scenarios do not imply a winningSide
11260
- matchUpStatus && isActiveMatchUpStatus({ matchUpStatus }) && ![DEFAULTED, WALKOVER$1, IN_PROGRESS].includes(matchUpStatus);
11261
- }
11262
-
11263
- function getStructureDrawPositionProfiles(params) {
11264
- const { drawDefinition, findContainer, structureId, event } = params;
11265
- let structure = params.structure;
11266
- const matchUpFilters = { isCollectionMatchUp: false };
11267
- const { containedStructures } = getContainedStructures({ drawDefinition });
11268
- const containedStructureIds = structureId ? containedStructures[structureId] || [] : [];
11269
- if (!structure) {
11270
- const result = findStructure({ drawDefinition, structureId });
11271
- if (result.error)
11272
- return result;
11273
- structure = findContainer ? result.containingStructure || result.structure : result.structure;
11274
- }
11275
- if (isAdHoc({ drawDefinition, structure })) {
11276
- return { structure, isAdHoc: true, error: INVALID_DRAW_POSITION };
11277
- }
11278
- const { matchUps: inContextDrawMatchUps } = getAllDrawMatchUps({
11279
- inContext: true,
11280
- matchUpFilters,
11281
- drawDefinition,
11282
- event
11283
- });
11284
- const inContextStructureMatchUps = inContextDrawMatchUps?.filter(
11285
- (matchUp) => matchUp.structureId === structureId || containedStructureIds.includes(matchUp.structureId)
11239
+ const eventSeedAssignments = {};
11240
+ const getScaleAccessor = (scaleName) => [SCALE, SEEDING, event.eventType, scaleName].join(".");
11241
+ const seedingScales = Object.assign(
11242
+ {},
11243
+ ...(participant.timeItems || []).filter(({ itemType }) => itemType.split(".")[1] === SEEDING).map(({ itemType: seedingScaleName, itemValue: seedValue }) => ({
11244
+ [seedingScaleName]: seedValue
11245
+ }))
11286
11246
  );
11287
- const { matchUpDependencies } = getMatchUpDependencies({
11288
- drawIds: [drawDefinition.drawId],
11289
- matchUps: inContextDrawMatchUps,
11290
- drawDefinition
11291
- });
11292
- const activeDependentMatchUpIdsCollection = [];
11293
- const drawPositionsCollection = [];
11294
- const drawPositionInitialRounds = {};
11295
- const activeMatchUps = [];
11296
- for (const matchUp of inContextDrawMatchUps || []) {
11297
- if (matchUp.structureId === structureId || containedStructureIds.includes(matchUp.structureId)) {
11298
- drawPositionsCollection.push(...matchUp.drawPositions || []);
11299
- const roundNumber = matchUp.roundNumber;
11300
- for (const drawPosition of (matchUp.drawPositions || []).filter(
11301
- Boolean
11302
- )) {
11303
- if (!drawPositionInitialRounds[drawPosition] || roundNumber && drawPositionInitialRounds[drawPosition] > roundNumber) {
11304
- drawPositionInitialRounds[drawPosition] = roundNumber;
11305
- }
11247
+ const eventSeedingScaleNames = (publishedSeeding?.stageSeedingScaleNames && Object.values(publishedSeeding?.stageSeedingScaleNames) || Array.isArray(publishedSeeding?.seedingScaleNames) && publishedSeeding.seedingScaleNames || []).map(getScaleAccessor);
11248
+ const publishedEventSeedingScaleNames = intersection(
11249
+ Object.keys(seedingScales),
11250
+ eventSeedingScaleNames
11251
+ );
11252
+ const eventSeedingPublished = !!(!usePublishState || !Object.keys(seedingScales).length && !publishedSeeding?.drawIds?.length || publishedEventSeedingScaleNames.length);
11253
+ if (eventSeedingPublished && publishedEventSeedingScaleNames.length) {
11254
+ if (publishedSeeding?.stageSeedingScaleNames) {
11255
+ const scaleValues = Object.keys(publishedSeeding.stageSeedingScaleNames).map((key) => {
11256
+ const accessor = getScaleAccessor(
11257
+ publishedSeeding.stageSeedingScaleNames[key]
11258
+ );
11259
+ const scaleValue = seedingScales[accessor];
11260
+ return [key, scaleValue];
11261
+ }).filter((pair) => pair[1]).map((pair) => ({ [pair[0]]: { seedValue: pair[1] } }));
11262
+ const seedAssignments = Object.assign({}, ...scaleValues);
11263
+ eventSeedAssignments.seedAssignments = seedAssignments;
11264
+ } else if (publishedEventSeedingScaleNames) {
11265
+ const seedValues = publishedEventSeedingScaleNames.map(
11266
+ (scaleName) => seedingScales[scaleName]
11267
+ );
11268
+ eventSeedAssignments.seedValue = seedValues.pop();
11269
+ }
11270
+ } else if (!usePublishState && typeof withSeeding === "object") {
11271
+ const scaleValues = Object.keys(withSeeding).map((key) => {
11272
+ const accessor = getScaleAccessor(withSeeding[key]);
11273
+ const scaleValue = seedingScales[accessor];
11274
+ return [key, scaleValue];
11275
+ }).filter((pair) => pair[1]).map((pair) => ({ [pair[0]]: { seedValue: pair[1] } }));
11276
+ const seedAssignments = Object.assign({}, ...scaleValues);
11277
+ eventSeedAssignments.seedAssignments = seedAssignments;
11278
+ } else {
11279
+ const { categoryName, ageCategoryCode } = event.category || {};
11280
+ let scaleItem;
11281
+ for (const scaleName of [ageCategoryCode, event.eventId, categoryName]) {
11282
+ const scaleAttributes = {
11283
+ eventType: event.eventType,
11284
+ scaleType: SEEDING,
11285
+ scaleName
11286
+ };
11287
+ const result = participantScaleItem({
11288
+ scaleAttributes,
11289
+ participant
11290
+ });
11291
+ if (result.scaleItem) {
11292
+ scaleItem = result.scaleItem;
11293
+ break;
11306
11294
  }
11307
11295
  }
11308
- if (isActiveMatchUp(matchUp)) {
11309
- activeMatchUps.push(matchUp);
11310
- activeDependentMatchUpIdsCollection.push(
11311
- matchUp.matchUpId,
11312
- ...matchUpDependencies?.[matchUp?.matchUpId]?.matchUpIds || []
11313
- );
11296
+ if (scaleItem) {
11297
+ const seedingPublished = !usePublishState || publishedSeeding?.published && // if drawIds have been specified then don't attach event seeding here
11298
+ // defer to seedValue that is in seedAssignments for draw in which participant appears
11299
+ !publishedSeeding?.published?.drawIds?.length;
11300
+ if (seedingPublished) {
11301
+ const seedValue = scaleItem.scaleValue;
11302
+ eventSeedAssignments.seedValue = seedValue;
11303
+ }
11314
11304
  }
11315
11305
  }
11316
- const drawPositions = unique(drawPositionsCollection.filter(Boolean)).sort(
11317
- numericSort
11318
- );
11319
- const activeDependentMatchUpIds = unique(activeDependentMatchUpIdsCollection);
11320
- const activeDrawPositions = unique(
11321
- inContextStructureMatchUps?.map(
11322
- ({ matchUpId, drawPositions: drawPositions2 }) => activeDependentMatchUpIds.includes(matchUpId) ? drawPositions2 : []
11323
- ).flat().filter(Boolean)
11324
- ).sort(numericSort);
11325
- const { positionAssignments } = getPositionAssignments({
11326
- drawDefinition,
11327
- structure
11328
- });
11329
- const byeDrawPositions = positionAssignments?.filter((assignment) => assignment.bye).map((assignment) => assignment.drawPosition);
11330
- const qualifyingDrawPositions = positionAssignments?.filter((assignment) => assignment.qualifier).map((assignment) => assignment.drawPosition);
11331
- const inactiveDrawPositions = drawPositions?.filter(
11332
- (drawPosition) => !activeDrawPositions.includes(drawPosition)
11333
- ) || [];
11334
- return {
11335
- allDrawPositions: drawPositions,
11336
- inContextStructureMatchUps,
11337
- drawPositionInitialRounds,
11338
- activeDependentMatchUpIds,
11339
- qualifyingDrawPositions,
11340
- inactiveDrawPositions,
11341
- positionAssignments,
11342
- activeDrawPositions,
11343
- byeDrawPositions,
11344
- activeMatchUps,
11345
- structure
11346
- };
11347
- }
11348
-
11349
- const hasParticipantId = (o) => o?.participantId;
11350
-
11351
- function getNumericSeedValue(seedValue) {
11352
- if (!seedValue)
11353
- return Infinity;
11354
- if (isConvertableInteger(seedValue))
11355
- return ensureInt(seedValue);
11356
- const firstValue = seedValue.split("-")[0];
11357
- if (isConvertableInteger(firstValue))
11358
- return ensureInt(firstValue);
11359
- return Infinity;
11306
+ return eventSeedAssignments;
11360
11307
  }
11361
11308
 
11362
- function getValidGroupSizes({
11363
- drawSize,
11364
- groupSizeLimit = 10
11309
+ function processEventEntry({
11310
+ extensionConversions,
11311
+ seedAssignments,
11312
+ participant,
11313
+ withSeeding,
11314
+ seedValue,
11315
+ eventId,
11316
+ ranking,
11317
+ entry
11365
11318
  }) {
11366
- const validGroupSizes = generateRange(3, groupSizeLimit + 1).filter(
11367
- (groupSize) => {
11368
- const groupsCount = Math.ceil(drawSize / groupSize);
11369
- const byesCount = groupsCount * groupSize - drawSize;
11370
- const maxParticipantsPerGroup = Math.ceil(drawSize / groupsCount);
11371
- const maxByesPerGroup = Math.ceil(byesCount / groupsCount);
11372
- return (!byesCount || byesCount < groupSize) && maxParticipantsPerGroup === groupSize && maxParticipantsPerGroup >= 3 && maxByesPerGroup < 2;
11373
- }
11319
+ const { entryStatus, entryStage, entryPosition, extensions } = entry;
11320
+ const entryExtensions = extensions?.length ? Object.assign({}, ...extensionsToAttributes(extensions)) : {};
11321
+ const attributes = Object.assign(entryExtensions, {
11322
+ ...extensionConversions,
11323
+ // this should be deprecated and clients should use derivedEventInfo
11324
+ entryPosition,
11325
+ entryStatus,
11326
+ entryStage,
11327
+ ranking,
11328
+ eventId
11329
+ });
11330
+ participant.events[eventId] = definedAttributes(
11331
+ attributes,
11332
+ false,
11333
+ false,
11334
+ true
11374
11335
  );
11375
- return { ...SUCCESS, validGroupSizes };
11336
+ if (withSeeding) {
11337
+ if (seedAssignments)
11338
+ participant.events[eventId].seedAssignments = seedAssignments;
11339
+ if (seedValue)
11340
+ participant.events[eventId].seedValue = seedValue;
11341
+ }
11376
11342
  }
11377
11343
 
11378
- function getSeedBlocks(params) {
11379
- const { roundRobinGroupsCount, participantsCount, cluster } = params;
11380
- if (!isConvertableInteger(participantsCount))
11381
- return {
11382
- seedBlocks: void 0,
11383
- ...decorateResult({
11384
- result: { error: INVALID_VALUES },
11385
- context: { participantsCount },
11386
- stack: "getSeedBlocks"
11387
- })
11388
- };
11389
- const drawSize = nextPowerOf2(participantsCount);
11390
- if (roundRobinGroupsCount) {
11391
- const increment = Math.min(roundRobinGroupsCount, drawSize);
11392
- const seedBlocks2 = [];
11393
- let position = 1;
11394
- generateRange(0, increment).forEach(() => {
11395
- seedBlocks2.push([position]);
11396
- position++;
11344
+ function addScheduleItem(params) {
11345
+ const {
11346
+ participantMap,
11347
+ participantId,
11348
+ matchUpStatus,
11349
+ roundPosition,
11350
+ structureId,
11351
+ matchUpType,
11352
+ roundNumber,
11353
+ matchUpId,
11354
+ potential,
11355
+ schedule,
11356
+ drawId,
11357
+ score
11358
+ } = params;
11359
+ if (!schedule || !Object.keys(schedule).length)
11360
+ return;
11361
+ const ignoreMatchUp = matchUpStatus === BYE;
11362
+ if (!ignoreMatchUp) {
11363
+ participantMap[participantId].scheduleItems.push({
11364
+ ...schedule,
11365
+ scheduledDate: extractDate(schedule?.scheduledDate),
11366
+ scheduledTime: extractTime(schedule?.scheduledTime),
11367
+ scoreHasValue: scoreHasValue({ score }),
11368
+ matchUpStatus,
11369
+ roundPosition,
11370
+ structureId,
11371
+ matchUpType,
11372
+ roundNumber,
11373
+ matchUpId,
11374
+ potential,
11375
+ drawId
11397
11376
  });
11398
- while (position < drawSize) {
11399
- const range2 = generateRange(position, position + increment);
11400
- position += increment;
11401
- seedBlocks2.push(range2);
11377
+ }
11378
+ }
11379
+
11380
+ function addStructureParticipation({
11381
+ finishingPositionRange: matchUpFinishingPositionRanges = {},
11382
+ participantMap,
11383
+ finishingRound,
11384
+ participantWon,
11385
+ matchUpStatus,
11386
+ participantId,
11387
+ stageSequence,
11388
+ roundNumber,
11389
+ structureId,
11390
+ matchUpId,
11391
+ drawId,
11392
+ stage
11393
+ }) {
11394
+ const participantAggregator = participantMap[participantId];
11395
+ const diff = (range) => Math.abs(range[0] - range[1]);
11396
+ if (!participantAggregator.structureParticipation[structureId]) {
11397
+ participantAggregator.structureParticipation[structureId] = {
11398
+ rankingStage: stage,
11399
+ walkoverWinCount: 0,
11400
+ defaultWinCount: 0,
11401
+ stageSequence,
11402
+ winCount: 0,
11403
+ structureId,
11404
+ drawId
11405
+ };
11406
+ }
11407
+ const structureParticipation = participantAggregator.structureParticipation[structureId];
11408
+ const { winner, loser } = matchUpFinishingPositionRanges;
11409
+ const finishingPositionRange = participantWon ? winner : loser;
11410
+ if (participantWon) {
11411
+ structureParticipation.winCount += 1;
11412
+ if (matchUpStatus === WALKOVER$1) {
11413
+ structureParticipation.walkoverWinCount += 1;
11414
+ }
11415
+ if (matchUpStatus === DEFAULTED) {
11416
+ structureParticipation.defaultWinCount += 1;
11402
11417
  }
11403
- return { ...SUCCESS, seedBlocks: seedBlocks2 };
11404
11418
  }
11405
- const range = generateRange(1, drawSize + 1);
11406
- const positions = [];
11407
- let chunkSize = drawSize / 2;
11408
- while (chunkSize > 1) {
11409
- const chunks = chunkArray(range, chunkSize);
11410
- const chunksCount = chunks.length;
11411
- chunks.forEach((chunk, i) => {
11412
- let candidate;
11413
- const top = i < chunksCount / 2;
11414
- const isEven = i % 2 === 0;
11415
- const first = chunk[0];
11416
- const last = chunk[chunk.length - 1];
11417
- if (cluster && chunksCount > 4) {
11418
- if (chunksCount === 8) {
11419
- candidate = top ? last : first;
11420
- } else {
11421
- candidate = isEven ? first : last;
11422
- }
11423
- } else {
11424
- candidate = top ? first : last;
11425
- }
11426
- if (!overlap(chunk, positions)) {
11427
- positions.push(candidate);
11428
- }
11429
- });
11430
- chunkSize = chunkSize / 2;
11419
+ if (finishingPositionRange && (!structureParticipation.finishingPositionRange || diff(finishingPositionRange) < diff(structureParticipation.finishingPositionRange))) {
11420
+ structureParticipation.finishingPositionRange = finishingPositionRange;
11431
11421
  }
11432
- const remainingPositions = range.filter(
11433
- (position) => !positions.includes(position)
11434
- );
11435
- while (remainingPositions.length) {
11436
- if (remainingPositions.length % 2 === 0) {
11437
- positions.push(remainingPositions.pop());
11438
- } else {
11439
- positions.push(remainingPositions.shift());
11422
+ if (finishingRound) {
11423
+ if (!structureParticipation.finishingRound || finishingRound < structureParticipation.finishingRound) {
11424
+ structureParticipation.finishingMatchUpId = matchUpId;
11425
+ structureParticipation.finishingRound = finishingRound;
11426
+ structureParticipation.roundNumber = roundNumber;
11427
+ }
11428
+ if (finishingRound === 1) {
11429
+ structureParticipation.participantWon = participantWon;
11440
11430
  }
11441
11431
  }
11442
- const seedBlockSizes = generateRange(0, 20).map((x) => Math.pow(2, x));
11443
- seedBlockSizes.unshift(1);
11444
- const iterations = seedBlockSizes.indexOf(drawSize);
11445
- let sum = 0;
11446
- const seedBlocks = [];
11447
- generateRange(0, iterations).forEach((i) => {
11448
- seedBlocks.push(positions.slice(sum, sum + seedBlockSizes[i]));
11449
- sum += seedBlockSizes[i];
11450
- });
11451
- return { ...SUCCESS, seedBlocks };
11452
11432
  }
11453
- function getSeedGroups({
11454
- roundRobinGroupsCount,
11455
- drawSize
11456
- }) {
11457
- const stack = "getSeedGroups";
11458
- if (!isConvertableInteger(drawSize))
11459
- return {
11460
- seedGroups: void 0,
11461
- ...decorateResult({
11462
- result: { error: INVALID_VALUES },
11463
- context: { drawSize },
11464
- stack
11465
- })
11433
+
11434
+ function processSides(params) {
11435
+ const {
11436
+ withScheduleTimes,
11437
+ scheduleAnalysis,
11438
+ withTeamMatchUps,
11439
+ participantMap,
11440
+ withOpponents,
11441
+ withMatchUps,
11442
+ withEvents,
11443
+ withDraws,
11444
+ finishingPositionRange,
11445
+ finishingRound,
11446
+ matchUpStatus,
11447
+ stageSequence,
11448
+ roundNumber,
11449
+ structureId,
11450
+ score,
11451
+ stage,
11452
+ withRankingProfile,
11453
+ tieWinningSide,
11454
+ roundPosition,
11455
+ matchUpTieId,
11456
+ matchUpSides,
11457
+ collectionId,
11458
+ matchUpType,
11459
+ winningSide,
11460
+ matchUpId,
11461
+ schedule,
11462
+ eventId,
11463
+ drawId,
11464
+ sides
11465
+ } = params;
11466
+ const opponents = withOpponents && sides?.length === 2 && Object.assign(
11467
+ {},
11468
+ ...sides.map(({ sideNumber }, i) => {
11469
+ const opponentParticipantId = sides[1 - i].participantId;
11470
+ return sideNumber && {
11471
+ [sideNumber]: opponentParticipantId
11472
+ };
11473
+ }).filter(Boolean)
11474
+ );
11475
+ for (const side of sides) {
11476
+ const { participantId, sideNumber, bye } = side;
11477
+ if (bye)
11478
+ continue;
11479
+ const participantWon = winningSide === sideNumber;
11480
+ const getOpponentInfo = (opponentParticipantId) => {
11481
+ const opponent = participantMap[opponentParticipantId]?.participant;
11482
+ const participantType = opponent?.participantType;
11483
+ const info = [
11484
+ {
11485
+ participantId: opponentParticipantId,
11486
+ participantType
11487
+ }
11488
+ ];
11489
+ if (participantType !== TEAM_PARTICIPANT) {
11490
+ for (const participantId2 of opponent?.individualParticipantIds || []) {
11491
+ const participant = participantMap[participantId2]?.participant;
11492
+ info.push({
11493
+ participantType: participant?.participantType,
11494
+ participantId: participantId2
11495
+ });
11496
+ }
11497
+ }
11498
+ return info;
11466
11499
  };
11467
- if (roundRobinGroupsCount) {
11468
- if (!isConvertableInteger(roundRobinGroupsCount))
11469
- return {
11470
- seedGroups: void 0,
11471
- ...decorateResult({
11472
- context: { roundRobinGroupsCount },
11473
- result: { error: INVALID_VALUES },
11474
- stack
11475
- })
11500
+ const addMatchUp = (participantId2, opponentParticipantId) => {
11501
+ if (withMatchUps) {
11502
+ participantMap[participantId2].matchUps[matchUpId] = {
11503
+ participantWon,
11504
+ matchUpType,
11505
+ structureId,
11506
+ sideNumber,
11507
+ matchUpId,
11508
+ eventId,
11509
+ drawId,
11510
+ stage
11511
+ };
11512
+ if (withOpponents) {
11513
+ const opponentParticipantInfo = getOpponentInfo(
11514
+ opponentParticipantId
11515
+ );
11516
+ participantMap[participantId2].matchUps[matchUpId].opponentParticipantInfo = opponentParticipantInfo;
11517
+ }
11518
+ if (collectionId) {
11519
+ participantMap[participantId2].matchUps[matchUpId].collectionId = collectionId;
11520
+ }
11521
+ }
11522
+ if (withOpponents && opponentParticipantId) {
11523
+ participantMap[participantId2].opponents[opponentParticipantId] = {
11524
+ participantId: opponentParticipantId,
11525
+ matchUpId,
11526
+ eventId,
11527
+ drawId
11528
+ };
11529
+ }
11530
+ if (withRankingProfile) {
11531
+ addStructureParticipation({
11532
+ finishingPositionRange,
11533
+ participantMap,
11534
+ participantWon,
11535
+ finishingRound,
11536
+ matchUpStatus,
11537
+ participantId: participantId2,
11538
+ stageSequence,
11539
+ roundNumber,
11540
+ structureId,
11541
+ matchUpId,
11542
+ drawId,
11543
+ stage
11544
+ });
11545
+ }
11546
+ if (scheduleAnalysis || withScheduleTimes) {
11547
+ addScheduleItem({
11548
+ participantMap,
11549
+ participantId: participantId2,
11550
+ matchUpStatus,
11551
+ roundPosition,
11552
+ matchUpType,
11553
+ roundNumber,
11554
+ structureId,
11555
+ matchUpId,
11556
+ schedule,
11557
+ drawId,
11558
+ score
11559
+ });
11560
+ }
11561
+ };
11562
+ const addPartner = ({ participant, partnerParticipantId }) => {
11563
+ const addPartnerParticiapntId = (element, partnerParticipantId2) => {
11564
+ if (element) {
11565
+ if (!element.partnerParticipantIds)
11566
+ element.partnerParticipantIds = [];
11567
+ if (!element.partnerParticipantIds.includes(partnerParticipantId2))
11568
+ element.partnerParticipantIds.push(partnerParticipantId2);
11569
+ }
11476
11570
  };
11477
- let seedNumber = 1;
11478
- const roundsCount = Math.floor(drawSize / roundRobinGroupsCount);
11479
- const seedGroups = generateRange(0, roundsCount).map(() => {
11480
- const seedNumbers = generateRange(
11481
- seedNumber,
11482
- seedNumber + roundRobinGroupsCount
11483
- );
11484
- seedNumber += roundRobinGroupsCount;
11485
- return seedNumbers;
11486
- });
11487
- return { seedGroups };
11488
- } else {
11489
- const { seedBlocks } = getSeedBlocks({
11490
- participantsCount: drawSize,
11491
- roundRobinGroupsCount
11492
- });
11493
- let seedNumber = 0;
11494
- const seedGroups = (seedBlocks || []).map(
11495
- (seedBlock) => (seedBlock || []).map(() => {
11496
- seedNumber += 1;
11497
- return seedNumber;
11498
- })
11499
- );
11500
- return { seedGroups };
11571
+ if (withDraws)
11572
+ addPartnerParticiapntId(
11573
+ participant?.draws?.[drawId],
11574
+ partnerParticipantId
11575
+ );
11576
+ if (withEvents) {
11577
+ addPartnerParticiapntId(
11578
+ participant?.events?.[eventId],
11579
+ partnerParticipantId
11580
+ );
11581
+ }
11582
+ if (withMatchUps) {
11583
+ addPartnerParticiapntId(
11584
+ participant?.matchUps?.[matchUpId],
11585
+ partnerParticipantId
11586
+ );
11587
+ }
11588
+ };
11589
+ if (participantId && participantMap[participantId]) {
11590
+ const opponentParticipantId = opponents?.[sideNumber];
11591
+ addMatchUp(participantId, opponentParticipantId);
11592
+ const isPair = participantMap[participantId]?.participant.participantType === PAIR;
11593
+ const individualParticipantIds = participantMap[participantId]?.participant.individualParticipantIds || [];
11594
+ if (matchUpTieId) {
11595
+ if (withTeamMatchUps) {
11596
+ const addTeamMatchUp = (participantId2) => participantMap[participantId2].matchUps[matchUpTieId] = {
11597
+ participantWon: tieWinningSide === sideNumber,
11598
+ matchUpType: TypeEnum.Team,
11599
+ matchUpId: matchUpTieId,
11600
+ sideNumber
11601
+ };
11602
+ addTeamMatchUp(participantId);
11603
+ individualParticipantIds.forEach(addTeamMatchUp);
11604
+ }
11605
+ if (withDraws && !participantMap[participantId].draws[drawId]) {
11606
+ const teamParticipantId = matchUpSides.find(
11607
+ (s) => s.sideNumber === sideNumber
11608
+ )?.participant?.participantId;
11609
+ const teamEntryStatus = participantMap[teamParticipantId]?.draws?.[drawId]?.entryStatus;
11610
+ const addDrawData = (participantId2) => participantMap[participantId2].draws[drawId] = {
11611
+ entryStatus: teamEntryStatus,
11612
+ // add positions played in lineUp collections
11613
+ eventId,
11614
+ drawId
11615
+ };
11616
+ addDrawData(participantId);
11617
+ individualParticipantIds.forEach(addDrawData);
11618
+ }
11619
+ }
11620
+ if (isPair) {
11621
+ individualParticipantIds.forEach(
11622
+ (participantId2) => participantMap[participantId2] && addMatchUp(participantId2, opponentParticipantId)
11623
+ );
11624
+ individualParticipantIds.forEach((participantId2, i) => {
11625
+ const partnerParticipantId = individualParticipantIds[1 - i];
11626
+ const participant = participantMap[participantId2];
11627
+ participant && addPartner({ participant, partnerParticipantId });
11628
+ });
11629
+ if (withEvents && matchUpSides) {
11630
+ const teamParticipantId = matchUpSides.find(
11631
+ (s) => s.sideNumber === sideNumber
11632
+ )?.participant?.participantId;
11633
+ if (teamParticipantId) {
11634
+ const teamEntry = participantMap[teamParticipantId]?.events[eventId];
11635
+ if (teamEntry) {
11636
+ participantMap[participantId].events[eventId] = { ...teamEntry };
11637
+ individualParticipantIds.forEach(
11638
+ (individualParticiapntId) => participantMap[individualParticiapntId].events[eventId] = {
11639
+ ...teamEntry
11640
+ }
11641
+ );
11642
+ } else {
11643
+ console.log("Missing teamEntry", { eventId, teamParticipantId });
11644
+ }
11645
+ }
11646
+ }
11647
+ }
11648
+ if (winningSide) {
11649
+ const processParticipantId = (id) => {
11650
+ if (participantWon) {
11651
+ participantMap[id].counters[matchUpType].wins += 1;
11652
+ participantMap[id].counters.wins += 1;
11653
+ if (matchUpStatus === WALKOVER$1) {
11654
+ participantMap[id].counters[matchUpType].walkoverWins += 1;
11655
+ participantMap[id].counters.walkoverWins += 1;
11656
+ }
11657
+ if (matchUpStatus === DEFAULTED) {
11658
+ participantMap[id].counters[matchUpType].defaultWins += 1;
11659
+ participantMap[id].counters.defaultWins += 1;
11660
+ }
11661
+ } else {
11662
+ participantMap[id].counters[matchUpType].losses += 1;
11663
+ participantMap[id].counters.losses += 1;
11664
+ if (matchUpStatus === WALKOVER$1) {
11665
+ participantMap[id].counters[matchUpType].walkovers += 1;
11666
+ participantMap[id].counters.walkovers += 1;
11667
+ }
11668
+ if (matchUpStatus === DEFAULTED) {
11669
+ participantMap[id].counters[matchUpType].defaults += 1;
11670
+ participantMap[id].counters.defaults += 1;
11671
+ }
11672
+ }
11673
+ };
11674
+ processParticipantId(participantId);
11675
+ individualParticipantIds.forEach(processParticipantId);
11676
+ }
11677
+ }
11501
11678
  }
11502
11679
  }
11503
11680
 
11504
- function getValidSeedBlocks({
11505
- provisionalPositioning,
11506
- appliedPolicies,
11507
- drawDefinition,
11508
- allPositions,
11509
- structure
11510
- }) {
11511
- let validSeedBlocks = [];
11512
- if (!structure)
11513
- return { error: MISSING_STRUCTURE };
11514
- const { matchUps, roundMatchUps } = getAllStructureMatchUps({
11515
- matchUpFilters: { roundNumbers: [1] },
11516
- provisionalPositioning,
11517
- structure
11518
- });
11519
- const { seedAssignments } = getStructureSeedAssignments({
11520
- provisionalPositioning,
11521
- drawDefinition,
11522
- structure
11523
- });
11524
- const { positionAssignments } = structureAssignedDrawPositions({ structure });
11525
- const positionsCount = positionAssignments?.length;
11526
- const seedsCount = seedAssignments?.length ?? 0;
11527
- let allDrawPositions = [];
11528
- const roundNumbers = Object.keys(roundMatchUps).map((n) => parseInt(n)).sort((a, b) => a - b);
11529
- const uniqueDrawPositionsByRound = roundNumbers.map((roundNumber) => {
11530
- const roundDrawPositions = roundMatchUps[roundNumber].map((matchUp) => matchUp.drawPositions).flat(Infinity).filter(Boolean);
11531
- const uniqueRoundDrawPositions = roundDrawPositions.filter(
11532
- (drawPosition) => !allDrawPositions.includes(drawPosition)
11681
+ function getParticipantEntries(params) {
11682
+ const {
11683
+ participantFilters,
11684
+ convertExtensions,
11685
+ policyDefinitions,
11686
+ tournamentRecord,
11687
+ usePublishState,
11688
+ contextProfile,
11689
+ participantMap,
11690
+ withPotentialMatchUps,
11691
+ withRankingProfile,
11692
+ withScheduleTimes,
11693
+ withScheduleItems,
11694
+ scheduleAnalysis,
11695
+ withTeamMatchUps,
11696
+ withStatistics,
11697
+ withOpponents,
11698
+ withMatchUps,
11699
+ withSeeding,
11700
+ withEvents,
11701
+ withDraws
11702
+ } = params;
11703
+ if (withScheduleItems)
11704
+ console.log({ withScheduleItems });
11705
+ const targetParticipantIds = participantFilters?.participantIds;
11706
+ const getRelevantParticipantIds = (participantId) => {
11707
+ const relevantParticipantIds = [participantId];
11708
+ relevantParticipantIds.push(participantId);
11709
+ participantMap[participantId]?.participant.individualParticipantIds?.forEach(
11710
+ (individualParticiapntId) => relevantParticipantIds.push(individualParticiapntId)
11533
11711
  );
11534
- allDrawPositions = allDrawPositions.concat(...roundDrawPositions);
11535
- return uniqueRoundDrawPositions;
11536
- }).filter((f) => f.length).reverse();
11537
- const firstRoundDrawPositions = uniqueDrawPositionsByRound.pop();
11538
- const firstRoundDrawPositionOffset = firstRoundDrawPositions && Math.min(...firstRoundDrawPositions) - 1 || 0;
11539
- const seedingProfile = appliedPolicies?.seeding?.seedingProfile;
11540
- const baseDrawSize = firstRoundDrawPositions?.length || 0;
11541
- const seedRangeDrawPositionBlocks = uniqueDrawPositionsByRound.filter(
11542
- (block) => block.filter((drawPosition) => drawPosition <= seedsCount).length
11543
- );
11544
- const { stage, structureType, roundLimit } = structure;
11545
- const isContainer = structureType === CONTAINER;
11546
- const isFeedIn = !isContainer && uniqueDrawPositionsByRound?.length;
11547
- const qualifyingBlocks = !isContainer && stage === QUALIFYING && roundLimit;
11548
- const fedSeedBlockPositions = seedRangeDrawPositionBlocks.flat(Infinity);
11549
- const fedSeedNumberOffset = isFeedIn ? fedSeedBlockPositions?.length : 0;
11550
- const countLimit = allPositions ? positionsCount : seedsCount;
11551
- const isLuckyStructure = isLucky({
11552
- drawDefinition,
11553
- structure,
11554
- matchUps
11555
- });
11556
- const firstRoundSeedsCount = isLuckyStructure ? 0 : !isFeedIn && countLimit || countLimit && fedSeedBlockPositions.length < countLimit && countLimit - fedSeedBlockPositions.length || 0;
11557
- if (qualifyingBlocks) {
11558
- const seedingBlocksCount = structure?.matchUps ? structure.matchUps.filter(
11559
- ({ roundNumber }) => roundNumber === structure.roundLimit
11560
- ).length : 0;
11561
- const chunkSize = firstRoundDrawPositions.length / seedingBlocksCount;
11562
- if (isFeedIn) ; else {
11563
- const positioning = getSeedPattern(seedingProfile);
11564
- const drawPositionChunks = chunkArray(firstRoundDrawPositions, chunkSize);
11565
- let groupNumber = 1;
11566
- const seedGroups = generateRange(0, drawPositionChunks[0].length).map(
11567
- () => {
11568
- const seedNumbers = generateRange(
11569
- groupNumber,
11570
- groupNumber + drawPositionChunks.length
11571
- );
11572
- groupNumber += drawPositionChunks.length;
11573
- return seedNumbers;
11712
+ return relevantParticipantIds.some(
11713
+ (obj) => !targetParticipantIds?.length || targetParticipantIds.includes(obj.relevantParticipantId)
11714
+ ) ? relevantParticipantIds : [];
11715
+ };
11716
+ const withOpts = {
11717
+ withMatchUps: withMatchUps || withRankingProfile,
11718
+ withEvents: withEvents || withRankingProfile,
11719
+ withDraws: withDraws || withRankingProfile,
11720
+ withPotentialMatchUps,
11721
+ withRankingProfile,
11722
+ withScheduleTimes,
11723
+ scheduleAnalysis,
11724
+ withTeamMatchUps,
11725
+ withStatistics,
11726
+ participantMap,
11727
+ withOpponents,
11728
+ withSeeding
11729
+ };
11730
+ const participantIdsWithConflicts = [];
11731
+ const mappedMatchUps = {};
11732
+ const matchUps = [];
11733
+ const eventsPublishStatuses = {};
11734
+ const derivedEventInfo = {};
11735
+ const derivedDrawInfo = {};
11736
+ const getRanking = ({ eventType, scaleNames, participantId }) => participantMap[participantId].participant?.rankings?.[eventType]?.find(
11737
+ (ranking) => scaleNames.includes(ranking.scaleName)
11738
+ )?.scaleValue;
11739
+ for (const event of tournamentRecord?.events || []) {
11740
+ if (participantFilters?.eventIds && !participantFilters.eventIds.includes(event.eventId))
11741
+ continue;
11742
+ const {
11743
+ drawDefinitions = [],
11744
+ extensions = [],
11745
+ eventType,
11746
+ eventName,
11747
+ category,
11748
+ entries,
11749
+ eventId,
11750
+ gender
11751
+ } = event;
11752
+ const { flightProfile } = getFlightProfile({ event });
11753
+ const flights = flightProfile?.flights ?? [];
11754
+ const publishStatuses = getEventPublishStatuses({ event });
11755
+ const publishedSeeding = publishStatuses?.publishedSeeding;
11756
+ if (publishStatuses)
11757
+ eventsPublishStatuses[eventId] = publishStatuses;
11758
+ if (withEvents || withSeeding || withRankingProfile) {
11759
+ const extensionConversions = convertExtensions ? Object.assign({}, ...extensionsToAttributes(extensions)) : {};
11760
+ derivedEventInfo[eventId] = {
11761
+ ...extensionConversions,
11762
+ eventName,
11763
+ eventType,
11764
+ category,
11765
+ eventId,
11766
+ gender
11767
+ };
11768
+ const scaleNames = [
11769
+ category?.categoryName,
11770
+ category?.ageCategoryCode
11771
+ ].filter(Boolean);
11772
+ for (const entry of entries) {
11773
+ const { participantId } = entry;
11774
+ if (!participantId || !participantMap[participantId])
11775
+ continue;
11776
+ const ranking = getRanking({ eventType, scaleNames, participantId });
11777
+ let seedAssignments, seedValue;
11778
+ if (withSeeding) {
11779
+ const participant = participantMap[participantId].participant;
11780
+ ({ seedAssignments, seedValue } = getEventSeedAssignments({
11781
+ publishedSeeding,
11782
+ usePublishState,
11783
+ withSeeding,
11784
+ participant,
11785
+ event
11786
+ }));
11574
11787
  }
11575
- );
11576
- ({ validSeedBlocks } = getSeedBlockPattern({
11577
- drawPositionBlocks: drawPositionChunks,
11578
- positioning,
11579
- seedGroups
11580
- }));
11788
+ const addEventEntry = (id) => {
11789
+ if (participantMap[id]?.events?.[eventId])
11790
+ return;
11791
+ const participant = participantMap[id];
11792
+ processEventEntry({
11793
+ extensionConversions,
11794
+ seedAssignments,
11795
+ participant,
11796
+ withSeeding,
11797
+ seedValue,
11798
+ eventId,
11799
+ ranking,
11800
+ entry
11801
+ });
11802
+ };
11803
+ addEventEntry(participantId);
11804
+ const individualParticipantIds = participantMap[participantId].participant.individualParticipantIds || [];
11805
+ individualParticipantIds.forEach(addEventEntry);
11806
+ }
11807
+ }
11808
+ const eventPublishedSeeding = eventsPublishStatuses?.[eventId]?.publishedSeeding;
11809
+ if (withDraws || withRankingProfile || withSeeding) {
11810
+ const getSeedingMap = (assignments) => assignments ? Object.assign(
11811
+ {},
11812
+ ...assignments.map(
11813
+ ({ participantId, seedValue, seedNumber }) => ({
11814
+ [participantId]: { seedValue, seedNumber }
11815
+ })
11816
+ )
11817
+ ) : void 0;
11818
+ const drawIds = unique([
11819
+ ...drawDefinitions.map(extractAttributes("drawId")),
11820
+ ...flights.map(extractAttributes("drawId"))
11821
+ ]);
11822
+ for (const drawId of drawIds) {
11823
+ const drawDefinition = drawDefinitions.find(
11824
+ (drawDefinition2) => drawDefinition2.drawId === drawId
11825
+ );
11826
+ const flight = flights?.find((flight2) => flight2.drawId === drawId);
11827
+ const entries2 = drawDefinition?.entries || flight?.drawEntries;
11828
+ const {
11829
+ structures = [],
11830
+ drawOrder,
11831
+ drawName,
11832
+ drawType
11833
+ } = drawDefinition ?? {};
11834
+ const flightNumber = flight?.flightNumber;
11835
+ const scaleNames = [
11836
+ category?.categoryName,
11837
+ category?.ageCategoryCode
11838
+ ].filter(Boolean);
11839
+ const orderedStructureIds = (drawDefinition?.structures || []).sort((a, b) => structureSort(a, b)).map(({ structureId, structures: structures2 }) => {
11840
+ return [
11841
+ structureId,
11842
+ ...(structures2 || []).map(({ structureId: structureId2 }) => structureId2)
11843
+ ];
11844
+ }).flat(Infinity);
11845
+ let qualifyingPositionAssignments, qualifyingSeedAssignments, mainPositionAssignments, mainSeedAssignments, drawSize = 0;
11846
+ const assignedParticipantIds = structures.filter(
11847
+ ({ stage, stageSequence }) => stage === MAIN && stageSequence === 1 || stage === QUALIFYING
11848
+ ).flatMap((structure) => {
11849
+ const { seedAssignments, stageSequence, stage } = structure;
11850
+ const { positionAssignments } = getPositionAssignments({
11851
+ structure
11852
+ });
11853
+ if (stage === MAIN) {
11854
+ drawSize = positionAssignments?.length ?? 0;
11855
+ mainPositionAssignments = positionAssignments;
11856
+ mainSeedAssignments = seedAssignments;
11857
+ } else if (stageSequence === 1) {
11858
+ qualifyingPositionAssignments = positionAssignments;
11859
+ qualifyingSeedAssignments = seedAssignments;
11860
+ }
11861
+ return positionAssignments;
11862
+ }).map(({ participantId }) => participantId).filter(Boolean);
11863
+ const mainSeedingMap = getSeedingMap(mainSeedAssignments);
11864
+ const qualifyingSeedingMap = getSeedingMap(qualifyingSeedAssignments);
11865
+ const relevantEntries = !drawDefinition ? entries2 : entries2.filter(
11866
+ ({ participantId }) => assignedParticipantIds.includes(participantId)
11867
+ );
11868
+ const seedingPublished = !usePublishState || eventPublishedSeeding?.published && (eventPublishedSeeding?.drawIds?.length === 0 || eventPublishedSeeding?.drawIds?.includes(drawId));
11869
+ for (const entry of relevantEntries) {
11870
+ const { entryStatus, entryStage, entryPosition, participantId } = entry;
11871
+ const ranking = getRanking({
11872
+ participantId,
11873
+ scaleNames,
11874
+ eventType
11875
+ });
11876
+ const addDrawEntry = (id) => {
11877
+ if (participantMap[id].draws?.[drawId])
11878
+ return;
11879
+ const includeSeeding = withSeeding && seedingPublished;
11880
+ const seedAssignments = includeSeeding ? {} : void 0;
11881
+ const mainSeeding = includeSeeding ? mainSeedingMap?.[participantId]?.seedValue || mainSeedingMap?.[participantId]?.seedNumber : void 0;
11882
+ const mainSeedingAssignments = mainSeeding ? mainSeedingMap?.[participantId] : void 0;
11883
+ const qualifyingSeeding = includeSeeding ? qualifyingSeedingMap?.[participantId]?.seedValue || qualifyingSeedingMap?.[participantId]?.seedNumber : void 0;
11884
+ const qualifyingSeedingAssignments = qualifyingSeeding ? qualifyingSeedingMap?.[participantId] : void 0;
11885
+ if (seedAssignments && mainSeeding)
11886
+ seedAssignments[MAIN] = mainSeedingAssignments;
11887
+ if (seedAssignments && qualifyingSeeding)
11888
+ seedAssignments[QUALIFYING] = qualifyingSeedingAssignments;
11889
+ const seedValue = mainSeeding || qualifyingSeeding;
11890
+ if (seedValue) {
11891
+ if (!participantMap[id].participant.seedings[eventType])
11892
+ participantMap[id].participant.seedings[eventType] = [];
11893
+ if (mainSeedingAssignments) {
11894
+ participantMap[id].participant.seedings[eventType].push({
11895
+ ...mainSeedingAssignments,
11896
+ scaleName: drawId
11897
+ });
11898
+ }
11899
+ if (qualifyingSeedingAssignments) {
11900
+ participantMap[id].participant.seedings[eventType].push({
11901
+ ...qualifyingSeedingAssignments,
11902
+ scaleName: drawId
11903
+ });
11904
+ }
11905
+ if (seedAssignments) {
11906
+ if (!participantMap[id].events[eventId].seedAssignments)
11907
+ participantMap[id].events[eventId].seedAssignments = {};
11908
+ Object.keys(seedAssignments).forEach(
11909
+ (stage) => participantMap[id].events[eventId].seedAssignments[stage] = seedAssignments[stage]
11910
+ );
11911
+ }
11912
+ }
11913
+ if ((withEvents || withRankingProfile) && participantMap[id] && eventId) {
11914
+ if (!participantMap[id].events[eventId])
11915
+ participantMap[id].events[eventId] = {};
11916
+ if (includeSeeding) {
11917
+ participantMap[id].events[eventId].seedValue = seedValue;
11918
+ } else if (participantMap[id].events[eventId].seedValue) {
11919
+ participantMap[id].events[eventId].seedValue = void 0;
11920
+ }
11921
+ }
11922
+ if (withDraws || withRankingProfile) {
11923
+ participantMap[id].draws[drawId] = definedAttributes(
11924
+ {
11925
+ seedAssignments,
11926
+ entryPosition,
11927
+ entryStatus,
11928
+ entryStage,
11929
+ eventId,
11930
+ ranking,
11931
+ drawId
11932
+ },
11933
+ false,
11934
+ false,
11935
+ true
11936
+ );
11937
+ }
11938
+ };
11939
+ if (![UNGROUPED, UNPAIRED].includes(entryStatus)) {
11940
+ addDrawEntry(participantId);
11941
+ const individualParticipantIds = participantMap[participantId].participant.individualParticipantIds || [];
11942
+ individualParticipantIds?.forEach(addDrawEntry);
11943
+ }
11944
+ }
11945
+ derivedDrawInfo[drawId] = {
11946
+ qualifyingPositionAssignments,
11947
+ qualifyingSeedAssignments,
11948
+ mainPositionAssignments,
11949
+ qualifyingSeedingMap,
11950
+ mainSeedAssignments,
11951
+ orderedStructureIds,
11952
+ mainSeedingMap,
11953
+ flightNumber,
11954
+ drawOrder,
11955
+ drawName,
11956
+ drawType,
11957
+ drawSize,
11958
+ drawId
11959
+ // qualifyingDrawSize,
11960
+ };
11961
+ }
11962
+ }
11963
+ if (withRankingProfile || scheduleAnalysis || withTeamMatchUps || withStatistics || withOpponents || withMatchUps || withDraws) {
11964
+ const nextMatchUps = !!scheduleAnalysis || withPotentialMatchUps;
11965
+ const eventMatchUps = allEventMatchUps({
11966
+ afterRecoveryTimes: !!scheduleAnalysis,
11967
+ policyDefinitions,
11968
+ tournamentRecord,
11969
+ inContext: true,
11970
+ contextProfile,
11971
+ participantMap,
11972
+ nextMatchUps,
11973
+ event
11974
+ })?.matchUps ?? [];
11975
+ for (const matchUp of eventMatchUps) {
11976
+ const {
11977
+ finishingPositionRange,
11978
+ potentialParticipants,
11979
+ tieMatchUps = [],
11980
+ sides = [],
11981
+ winningSide,
11982
+ matchUpType,
11983
+ matchUpId,
11984
+ eventId: eventId2,
11985
+ drawId,
11986
+ collectionId,
11987
+ stageSequence,
11988
+ finishingRound,
11989
+ matchUpStatus,
11990
+ roundPosition,
11991
+ roundNumber,
11992
+ structureId,
11993
+ schedule,
11994
+ score,
11995
+ stage
11996
+ } = matchUp;
11997
+ mappedMatchUps[matchUpId] = matchUp;
11998
+ const baseAttrs = {
11999
+ finishingPositionRange,
12000
+ finishingRound,
12001
+ stageSequence,
12002
+ roundPosition,
12003
+ collectionId,
12004
+ roundNumber,
12005
+ structureId,
12006
+ schedule,
12007
+ eventId: eventId2,
12008
+ drawId,
12009
+ score,
12010
+ stage
12011
+ };
12012
+ processSides({
12013
+ ...baseAttrs,
12014
+ ...withOpts,
12015
+ matchUpStatus,
12016
+ winningSide,
12017
+ matchUpType,
12018
+ matchUpId,
12019
+ sides
12020
+ });
12021
+ for (const tieMatchUp of tieMatchUps) {
12022
+ const {
12023
+ winningSide: tieMatchUpWinningSide,
12024
+ sides: tieMatchUpSides = [],
12025
+ matchUpId: tieMatchUpId,
12026
+ matchUpStatus: matchUpStatus2,
12027
+ matchUpType: matchUpType2
12028
+ } = tieMatchUp;
12029
+ processSides({
12030
+ ...baseAttrs,
12031
+ ...withOpts,
12032
+ winningSide: tieMatchUpWinningSide,
12033
+ tieWinningSide: winningSide,
12034
+ matchUpTieId: matchUpId,
12035
+ matchUpId: tieMatchUpId,
12036
+ sides: tieMatchUpSides,
12037
+ matchUpSides: sides,
12038
+ matchUpStatus: matchUpStatus2,
12039
+ matchUpType: matchUpType2
12040
+ });
12041
+ }
12042
+ if (Array.isArray(potentialParticipants) && (nextMatchUps || !!scheduleAnalysis || withScheduleTimes)) {
12043
+ const potentialParticipantIds = potentialParticipants.flat().map(extractAttributes("participantId")).filter(Boolean);
12044
+ potentialParticipantIds?.forEach((participantId) => {
12045
+ const relevantParticipantIds = getRelevantParticipantIds(participantId);
12046
+ relevantParticipantIds?.forEach((relevantParticipantId) => {
12047
+ if (!participantMap[relevantParticipantId]) {
12048
+ return;
12049
+ }
12050
+ participantMap[relevantParticipantId].potentialMatchUps[matchUpId] = definedAttributes({
12051
+ tournamentId: tournamentRecord?.tournamentId,
12052
+ matchUpId,
12053
+ eventId: eventId2,
12054
+ drawId
12055
+ });
12056
+ });
12057
+ if (!!scheduleAnalysis || withScheduleTimes) {
12058
+ addScheduleItem({
12059
+ potential: true,
12060
+ participantMap,
12061
+ participantId,
12062
+ matchUpStatus,
12063
+ roundPosition,
12064
+ structureId,
12065
+ matchUpType,
12066
+ roundNumber,
12067
+ matchUpId,
12068
+ schedule,
12069
+ drawId,
12070
+ score
12071
+ });
12072
+ }
12073
+ });
12074
+ }
12075
+ }
12076
+ matchUps.push(...eventMatchUps);
11581
12077
  }
11582
- } else if (isContainer) {
11583
- const result = getContainerBlocks({
11584
- seedingProfile,
11585
- structure
11586
- });
11587
- ({ validSeedBlocks } = result);
11588
- } else if (isFeedIn) {
11589
- validSeedBlocks = seedRangeDrawPositionBlocks.map((block) => {
11590
- return { seedNumbers: block, drawPositions: block };
11591
- });
11592
- } else if (isLuckyStructure) {
11593
- const blocks = chunkArray(firstRoundDrawPositions, 2).map((block, i) => ({
11594
- drawPositions: [block[0]],
11595
- seedNumbers: [i + 1]
11596
- }));
11597
- blocks.forEach((block) => validSeedBlocks.push(block));
11598
- }
11599
- if (!isContainer && !isLuckyStructure && !qualifyingBlocks) {
11600
- const { blocks } = constructPower2Blocks({
11601
- drawPositionOffset: firstRoundDrawPositionOffset,
11602
- seedNumberOffset: fedSeedNumberOffset,
11603
- seedCountGoal: firstRoundSeedsCount,
11604
- seedingProfile,
11605
- baseDrawSize
11606
- });
11607
- blocks.forEach((block) => validSeedBlocks.push(block));
11608
12078
  }
11609
- const seedDrawPositions = validSeedBlocks.flatMap(
11610
- (seedBlock) => seedBlock.drawPositions
11611
- );
11612
- const validSeedPositions = seedDrawPositions.reduce(
11613
- (result, drawPosition) => {
11614
- return firstRoundDrawPositions?.includes(drawPosition) && result;
11615
- },
11616
- true
11617
- );
11618
- if (!isLuckyStructure && !isFeedIn && !isContainer && !validSeedPositions) {
11619
- return {
11620
- error: INVALID_SEED_POSITION,
11621
- validSeedBlocks: [],
11622
- isContainer,
11623
- isFeedIn
11624
- };
12079
+ if (withStatistics || withRankingProfile || !!scheduleAnalysis) {
12080
+ const aggregators = Object.values(participantMap);
12081
+ for (const participantAggregator of aggregators) {
12082
+ const {
12083
+ wins,
12084
+ losses,
12085
+ [SINGLES$1]: { wins: singlesWins, losses: singlesLosses },
12086
+ [DOUBLES]: { wins: doublesWins, losses: doublesLosses }
12087
+ } = participantAggregator.counters;
12088
+ const addStatValue = (statCode, wins2, losses2) => {
12089
+ const denominator = wins2 + losses2;
12090
+ const numerator = wins2;
12091
+ const statValue = denominator && numerator / denominator;
12092
+ participantAggregator.statistics[statCode] = {
12093
+ denominator,
12094
+ numerator,
12095
+ statValue,
12096
+ statCode
12097
+ };
12098
+ };
12099
+ if (withStatistics) {
12100
+ addStatValue(WIN_RATIO, wins, losses);
12101
+ addStatValue(`${WIN_RATIO}.${SINGLES$1}`, singlesWins, singlesLosses);
12102
+ addStatValue(`${WIN_RATIO}.${DOUBLES}`, doublesWins, doublesLosses);
12103
+ }
12104
+ if (withRankingProfile) {
12105
+ const diff = (range = []) => Math.abs(range[0] - range[1]);
12106
+ for (const drawId of Object.keys(participantAggregator.draws)) {
12107
+ const { orderedStructureIds = [], flightNumber } = derivedDrawInfo[drawId] || {};
12108
+ if (participantAggregator.structureParticipation && orderedStructureIds.length) {
12109
+ let finishingPositionRange;
12110
+ let nonQualifyingOrder = 0;
12111
+ const orderedParticipation = orderedStructureIds.map((structureId) => {
12112
+ const participation = participantAggregator.structureParticipation[structureId];
12113
+ if (!participation)
12114
+ return;
12115
+ if (!finishingPositionRange)
12116
+ finishingPositionRange = participation?.finishingPositionRange;
12117
+ if (diff(finishingPositionRange) > diff(participation?.finishingPositionRange))
12118
+ finishingPositionRange = participation?.finishingPositionRange;
12119
+ const notQualifying = participation.stage !== QUALIFYING;
12120
+ if (notQualifying)
12121
+ nonQualifyingOrder += 1;
12122
+ const participationOrder = notQualifying ? nonQualifyingOrder : void 0;
12123
+ return definedAttributes({
12124
+ ...participation,
12125
+ participationOrder,
12126
+ flightNumber
12127
+ });
12128
+ }).filter(Boolean);
12129
+ if (participantAggregator.draws[drawId]) {
12130
+ participantAggregator.draws[drawId].finishingPositionRange = finishingPositionRange;
12131
+ participantAggregator.draws[drawId].structureParticipation = orderedParticipation;
12132
+ }
12133
+ }
12134
+ }
12135
+ }
12136
+ if (scheduleAnalysis) {
12137
+ const scheduledMinutesDifference = isObject(scheduleAnalysis) ? scheduleAnalysis.scheduledMinutesDifference : 0;
12138
+ const scheduleItems = participantAggregator.scheduleItems || [];
12139
+ const potentialMatchUps = participantAggregator.potentialMatchUps || {};
12140
+ const dateItems = scheduleItems.reduce((dateItems2, scheduleItem) => {
12141
+ const { scheduledDate, scheduledTime } = scheduleItem;
12142
+ if (!dateItems2[scheduledDate])
12143
+ dateItems2[scheduledDate] = [];
12144
+ if (scheduledTime)
12145
+ dateItems2[scheduledDate].push(scheduleItem);
12146
+ return dateItems2;
12147
+ }, {});
12148
+ Object.values(dateItems).forEach((items) => items.sort(timeSort));
12149
+ for (const scheduleItem of scheduleItems) {
12150
+ const {
12151
+ typeChangeTimeAfterRecovery,
12152
+ timeAfterRecovery,
12153
+ scheduledDate,
12154
+ scheduledTime
12155
+ } = scheduleItem;
12156
+ const scheduleItemsToConsider = dateItems[scheduledDate];
12157
+ const scheduledMinutes = timeStringMinutes(scheduledTime);
12158
+ for (const consideredItem of scheduleItemsToConsider) {
12159
+ const ignoreItem = consideredItem.matchUpId === scheduleItem.matchUpId || [WALKOVER$1, DEFAULTED].includes(consideredItem.matchUpStatus) && !consideredItem.scoreHasValue;
12160
+ if (ignoreItem)
12161
+ continue;
12162
+ const typeChange = scheduleItem.matchUpType !== consideredItem.matchUpType;
12163
+ const notBeforeTime = typeChange ? typeChangeTimeAfterRecovery || timeAfterRecovery : timeAfterRecovery;
12164
+ const sameDraw = scheduleItem.drawId === consideredItem.drawId;
12165
+ const bothPotential = potentialMatchUps[scheduleItem.matchUpId] && potentialMatchUps[consideredItem.matchUpId];
12166
+ const nextMinutes = timeStringMinutes(consideredItem.scheduledTime);
12167
+ const minutesDifference = Math.abs(nextMinutes - scheduledMinutes);
12168
+ const timeOverlap = scheduledMinutesDifference && !isNaN(scheduledMinutesDifference) ? minutesDifference <= scheduledMinutesDifference : timeStringMinutes(notBeforeTime) > timeStringMinutes(consideredItem.scheduledTime);
12169
+ if (timeOverlap && !(bothPotential && sameDraw)) {
12170
+ participantAggregator.scheduleConflicts.push({
12171
+ priorScheduledMatchUpId: consideredItem.matchUpId,
12172
+ matchUpIdWithConflict: scheduleItem.matchUpId
12173
+ });
12174
+ }
12175
+ }
12176
+ }
12177
+ const pid = participantAggregator.participant.participantId;
12178
+ if (participantAggregator.scheduleConflicts.length) {
12179
+ participantIdsWithConflicts.push(pid);
12180
+ }
12181
+ participantMap[pid].scheduleConflicts = participantAggregator.scheduleConflicts;
12182
+ }
12183
+ }
11625
12184
  }
11626
12185
  return {
11627
- isLuckyStructure,
11628
- validSeedBlocks,
11629
- isContainer,
11630
- isFeedIn
12186
+ participantIdsWithConflicts,
12187
+ eventsPublishStatuses,
12188
+ derivedEventInfo,
12189
+ derivedDrawInfo,
12190
+ mappedMatchUps,
12191
+ participantMap,
12192
+ matchUps
11631
12193
  };
11632
12194
  }
11633
- function getContainerBlocks({ seedingProfile, structure }) {
11634
- const containedStructures = structure.structures || [];
11635
- const roundRobinGroupsCount = containedStructures.length;
11636
- const positionAssignments = getPositionAssignments({
11637
- structure
11638
- })?.positionAssignments;
11639
- const positioning = getSeedPattern(seedingProfile);
11640
- const drawSize = positionAssignments?.length ?? 0;
11641
- const { seedGroups } = getSeedGroups({
11642
- roundRobinGroupsCount,
11643
- drawSize
12195
+
12196
+ function getParticipants(params) {
12197
+ const {
12198
+ withIndividualParticipants,
12199
+ participantFilters = {},
12200
+ withPotentialMatchUps,
12201
+ withRankingProfile,
12202
+ convertExtensions,
12203
+ policyDefinitions,
12204
+ withScheduleItems,
12205
+ tournamentRecord,
12206
+ scheduleAnalysis,
12207
+ withSignInStatus,
12208
+ withTeamMatchUps,
12209
+ withScaleValues,
12210
+ usePublishState,
12211
+ contextProfile,
12212
+ withStatistics,
12213
+ withOpponents,
12214
+ withMatchUps,
12215
+ internalUse,
12216
+ withSeeding,
12217
+ withEvents,
12218
+ withDraws,
12219
+ withISO2,
12220
+ withIOC
12221
+ } = params;
12222
+ if (!tournamentRecord)
12223
+ return { error: MISSING_TOURNAMENT_RECORD };
12224
+ if (withMatchUps || withRankingProfile) {
12225
+ getMatchUpDependencies({ tournamentRecord });
12226
+ }
12227
+ let { participantMap } = getParticipantMap({
12228
+ withIndividualParticipants,
12229
+ convertExtensions,
12230
+ tournamentRecord,
12231
+ withSignInStatus,
12232
+ withScaleValues,
12233
+ internalUse,
12234
+ withISO2,
12235
+ withIOC
11644
12236
  });
11645
- const drawPositionBlocks = containedStructures.map(
11646
- (containedStructure) => getPositionAssignments({
11647
- structure: containedStructure
11648
- }).positionAssignments?.map((assignment) => assignment.drawPosition)
11649
- );
11650
- return getSeedBlockPattern({
11651
- drawPositionBlocks,
11652
- positioning,
11653
- seedGroups
12237
+ const entriesResult = getParticipantEntries({
12238
+ withMatchUps: withMatchUps ?? withRankingProfile,
12239
+ withEvents: withEvents ?? withRankingProfile,
12240
+ withDraws: withDraws ?? withRankingProfile,
12241
+ withPotentialMatchUps,
12242
+ participantFilters,
12243
+ withRankingProfile,
12244
+ convertExtensions,
12245
+ withScheduleItems,
12246
+ policyDefinitions,
12247
+ tournamentRecord,
12248
+ scheduleAnalysis,
12249
+ withTeamMatchUps,
12250
+ usePublishState,
12251
+ withStatistics,
12252
+ participantMap,
12253
+ withOpponents,
12254
+ contextProfile,
12255
+ withSeeding
11654
12256
  });
11655
- }
11656
- function getSeedBlockPattern({ positioning, seedGroups, drawPositionBlocks }) {
11657
- const validSeedBlocks = [];
11658
- const topDown = (a, b) => a - b;
11659
- const bottomUp = (a, b) => b - a;
11660
- const assignedPositions = [];
11661
- seedGroups.forEach((seedGroup, i) => {
11662
- if (i && positioning !== WATERFALL) {
11663
- shuffleArray(seedGroup);
11664
- }
11665
- seedGroup.forEach((seedNumber, j) => {
11666
- const blockIndex = i % 2 ? drawPositionBlocks.length - j - 1 : j;
11667
- const drawPosition = drawPositionBlocks[blockIndex].sort(i % 2 ? bottomUp : topDown).find((drawPosition2) => !assignedPositions.includes(drawPosition2));
11668
- assignedPositions.push(drawPosition);
11669
- validSeedBlocks.push({
11670
- seedNumbers: [seedNumber],
11671
- drawPositions: [drawPosition]
11672
- });
11673
- });
11674
- });
11675
- return { validSeedBlocks };
11676
- }
11677
- function constructPower2Blocks(params) {
11678
- const {
11679
- drawPositionOffset = 0,
11680
- roundRobinGroupsCount,
11681
- seedNumberOffset = 0,
11682
- seedingProfile,
11683
- seedCountGoal,
11684
- baseDrawSize
11685
- } = params;
11686
- let count = 1;
11687
- const blocks = [];
11688
- const { seedBlocks } = getSeedBlocks({
11689
- cluster: getSeedPattern(seedingProfile) === CLUSTER,
11690
- participantsCount: baseDrawSize,
11691
- roundRobinGroupsCount
11692
- });
11693
- count = 0;
11694
- for (const seedBlock of seedBlocks) {
11695
- if (count + 1 > seedCountGoal)
11696
- break;
11697
- const drawPositions = seedBlock.map(
11698
- (drawPosition) => drawPosition + drawPositionOffset
11699
- );
11700
- const seedNumbers = getSeeds(count + 1, seedBlock.length).map(
11701
- (seedNumber) => +seedNumber + seedNumberOffset
11702
- );
11703
- count += seedBlock.length;
11704
- blocks.push({ drawPositions, seedNumbers });
11705
- }
11706
- return { blocks };
11707
- function getSeeds(s, n) {
11708
- return Array.from(new Array(n), (_, i) => i + s);
11709
- }
11710
- }
11711
- function isValidSeedPosition({
11712
- appliedPolicies,
11713
- drawDefinition,
11714
- seedBlockInfo,
11715
- drawPosition,
11716
- structureId,
11717
- seedNumber
11718
- }) {
11719
- const { structure } = findStructure({ drawDefinition, structureId });
11720
- if (!appliedPolicies) {
11721
- appliedPolicies = getAppliedPolicies({ drawDefinition }).appliedPolicies;
11722
- }
11723
- let validSeedBlocks = seedBlockInfo?.validSeedBlocks;
11724
- if (!validSeedBlocks && structure) {
11725
- validSeedBlocks = getValidSeedBlocks({
11726
- appliedPolicies,
11727
- drawDefinition,
11728
- structure
11729
- })?.validSeedBlocks;
11730
- }
11731
- if (appliedPolicies?.seeding?.validSeedPositions?.ignore)
11732
- return true;
11733
- if (appliedPolicies?.seeding?.validSeedPositions?.strict) {
11734
- const targetSeedBlock = validSeedBlocks.find(
11735
- (seedBlock) => seedBlock.seedNumbers.includes(seedNumber)
11736
- );
11737
- const validSeedPositions2 = targetSeedBlock?.drawPositions || [];
11738
- return validSeedPositions2.includes(drawPosition);
11739
- }
11740
- const validSeedPositions = [].concat(
11741
- ...validSeedBlocks.map((seedBlock) => seedBlock.drawPositions)
11742
- );
11743
- return validSeedPositions.includes(drawPosition);
11744
- }
11745
- function getNextSeedBlock(params) {
11746
12257
  const {
11747
- provisionalPositioning,
11748
- drawDefinition,
11749
- seedBlockInfo,
11750
- structureId,
11751
- randomize
11752
- } = params;
11753
- const { structure } = findStructure({ drawDefinition, structureId });
11754
- const { seedAssignments } = getStructureSeedAssignments({
11755
- provisionalPositioning,
11756
- drawDefinition,
11757
- structure
11758
- });
11759
- const { positionAssignments } = structureAssignedDrawPositions({ structure });
11760
- const positionsWithParticipants = positionAssignments?.filter(
11761
- (assignment) => assignment.participantId ?? assignment.bye ?? assignment.qualifier
12258
+ participantIdsWithConflicts,
12259
+ eventsPublishStatuses,
12260
+ derivedEventInfo,
12261
+ derivedDrawInfo,
12262
+ mappedMatchUps
12263
+ } = entriesResult;
12264
+ const matchUps = entriesResult.matchUps;
12265
+ participantMap = entriesResult.participantMap;
12266
+ const nextMatchUps = scheduleAnalysis ?? withPotentialMatchUps;
12267
+ const processedParticipants = Object.values(participantMap).map(
12268
+ ({
12269
+ potentialMatchUps,
12270
+ scheduleConflicts,
12271
+ participant,
12272
+ statistics,
12273
+ opponents,
12274
+ matchUps: matchUps2,
12275
+ events,
12276
+ draws
12277
+ }) => {
12278
+ const participantDraws = Object.values(draws);
12279
+ const participantOpponents = Object.values(opponents);
12280
+ if (withOpponents) {
12281
+ participantDraws?.forEach((draw) => {
12282
+ draw.opponents = participantOpponents.filter(
12283
+ (opponent) => opponent.drawId === draw.drawId
12284
+ );
12285
+ });
12286
+ }
12287
+ return definedAttributes(
12288
+ {
12289
+ ...participant,
12290
+ scheduleConflicts: scheduleAnalysis ? scheduleConflicts : void 0,
12291
+ draws: withDraws || withRankingProfile ? participantDraws : void 0,
12292
+ events: withEvents || withRankingProfile ? Object.values(events) : void 0,
12293
+ matchUps: withMatchUps || withRankingProfile ? Object.values(matchUps2) : void 0,
12294
+ opponents: withOpponents ? participantOpponents : void 0,
12295
+ potentialMatchUps: nextMatchUps ? Object.values(potentialMatchUps) : void 0,
12296
+ statistics: withStatistics ? Object.values(statistics) : void 0
12297
+ },
12298
+ false,
12299
+ false,
12300
+ true
12301
+ );
12302
+ }
11762
12303
  );
11763
- const assignedDrawPositions = positionsWithParticipants?.map((assignment) => assignment.drawPosition).filter(Boolean);
11764
- const { appliedPolicies } = getAppliedPolicies({ drawDefinition });
11765
- const validSeedBlocks = seedBlockInfo?.validSeedBlocks || structure && getValidSeedBlocks({
11766
- provisionalPositioning,
11767
- appliedPolicies,
11768
- drawDefinition,
11769
- structure
11770
- })?.validSeedBlocks;
11771
- const unfilledSeedBlocks = (validSeedBlocks || []).filter((seedBlock) => {
11772
- const unfilledPositions2 = seedBlock.drawPositions.filter(
11773
- (drawPosition) => !assignedDrawPositions?.includes(drawPosition)
11774
- );
11775
- return unfilledPositions2.length;
12304
+ const participantAttributes = policyDefinitions?.[POLICY_TYPE_PARTICIPANT];
12305
+ const template = participantAttributes?.participant;
12306
+ const filteredParticipants = filterParticipants({
12307
+ participants: processedParticipants,
12308
+ participantFilters,
12309
+ tournamentRecord
11776
12310
  });
11777
- const nextSeedBlock = unfilledSeedBlocks[0];
11778
- const assignedSeedParticipantIds = seedAssignments?.map((assignment) => assignment.participantId).filter(Boolean);
11779
- const assignedPositionParticipantIds = positionAssignments?.map((assignment) => assignment.participantId).filter(Boolean);
11780
- const placedSeedParticipantIds = assignedSeedParticipantIds?.filter(
11781
- (participantId) => assignedPositionParticipantIds?.includes(participantId)
11782
- );
11783
- const unplacedSeedIds = assignedSeedParticipantIds?.filter(
11784
- (participantId) => !assignedPositionParticipantIds?.includes(participantId)
11785
- );
11786
- const unplacedSeedAssignments = seedAssignments?.filter(
11787
- (assignment) => unplacedSeedIds?.includes(assignment.participantId)
11788
- );
11789
- const seedsWithoutDrawPositions = seedAssignments?.filter(
11790
- (assignment) => !assignment.participantId
11791
- );
11792
- const seedsLeftToAssign = unplacedSeedAssignments?.length && unplacedSeedAssignments.length > 0 ? unplacedSeedAssignments.length : seedsWithoutDrawPositions?.length ?? 0;
11793
- const unfilled = seedsLeftToAssign && nextSeedBlock?.drawPositions.filter(
11794
- (drawPosition) => !assignedDrawPositions?.includes(drawPosition)
11795
- ) || [];
11796
- const unfilledPositions = randomize ? shuffleArray(unfilled) : unfilled;
11797
- const selectedParticipantIds = [];
11798
- const randomlySelectedUnplacedSeedValueIds = unfilledPositions.map(() => {
11799
- const assignment = randomlySelectLowestSeedValue(
11800
- unplacedSeedAssignments,
11801
- selectedParticipantIds
11802
- );
11803
- const participantId = assignment?.participantId;
11804
- if (participantId)
11805
- selectedParticipantIds.push(participantId);
11806
- return participantId;
11807
- }).filter(Boolean);
11808
- const placedSeedNumbers = seedAssignments?.filter(
11809
- (assignment) => placedSeedParticipantIds?.includes(assignment.participantId)
11810
- ).map((assignment) => assignment.seedNumber);
11811
- const blockSeedNumbers = nextSeedBlock?.seedNumbers || [];
11812
- const unplacedSeedNumbers = blockSeedNumbers.filter(
11813
- (seedNumber) => !placedSeedNumbers?.includes(seedNumber)
11814
- );
11815
- const unplacedSeedNumberIds = seedAssignments?.filter(
11816
- (assignment) => unplacedSeedNumbers.includes(assignment.seedNumber)
11817
- ).map((assignment) => assignment.participantId);
11818
- const duplicateSeedNumbers = appliedPolicies?.seeding?.duplicateSeedNumbers;
11819
- const allowsDuplicateSeedNumbers = duplicateSeedNumbers !== void 0 ? duplicateSeedNumbers : true;
11820
- const unplacedSeedParticipantIds = allowsDuplicateSeedNumbers ? randomlySelectedUnplacedSeedValueIds : unplacedSeedNumberIds;
12311
+ const participants = template ? filteredParticipants.map(
12312
+ (source) => attributeFilter({ source, template })
12313
+ ) : filteredParticipants;
11821
12314
  return {
11822
- nextSeedBlock,
11823
- unplacedSeedParticipantIds,
11824
- unplacedSeedNumbers,
11825
- unfilledPositions,
11826
- unplacedSeedAssignments
12315
+ participantIdsWithConflicts,
12316
+ eventsPublishStatuses,
12317
+ derivedEventInfo,
12318
+ derivedDrawInfo,
12319
+ mappedMatchUps,
12320
+ participantMap,
12321
+ participants,
12322
+ ...SUCCESS,
12323
+ matchUps
11827
12324
  };
11828
- function randomlySelectLowestSeedValue(assignments, selectedParticipantIds2) {
11829
- const filteredAssignments = assignments.filter(
11830
- (assignment) => !selectedParticipantIds2.includes(assignment.participantId)
11831
- );
11832
- const lowestSeedValue = Math.min(
11833
- ...filteredAssignments.map(
11834
- (assignment) => getNumericSeedValue(assignment.seedValue)
11835
- )
11836
- );
11837
- const assignmentsWithLowestSeedValue = filteredAssignments.filter(
11838
- (assignment) => getNumericSeedValue(assignment.seedValue) === lowestSeedValue
11839
- );
11840
- const randomizedAssignments = shuffleArray(assignmentsWithLowestSeedValue);
11841
- return randomizedAssignments.pop();
11842
- }
11843
- }
11844
- function getSeedPattern(seedingProfile) {
11845
- if (typeof seedingProfile === "string")
11846
- return seedingProfile;
11847
- if (typeof seedingProfile === "object")
11848
- return seedingProfile.positioning;
11849
12325
  }
11850
12326
 
11851
- const hasSchedule = ({
11852
- scheduleAttributes = ["scheduledDate", "scheduledTime"],
11853
- schedule = {}
11854
- }) => {
11855
- const matchUpScheduleKeys = Object.keys(schedule).filter((key) => scheduleAttributes.includes(key)).filter((key) => schedule[key]);
11856
- return !!matchUpScheduleKeys.length;
11857
- };
11858
-
11859
12327
  function getDerivedPositionAssignments({
11860
12328
  derivedDrawInfo,
11861
12329
  participantId,
@@ -11936,6 +12404,14 @@ function getDerivedSeedAssignments({
11936
12404
  return Object.keys(seedAssignments).length ? seedAssignments : void 0;
11937
12405
  }
11938
12406
 
12407
+ const hasSchedule = ({
12408
+ scheduleAttributes = ["scheduledDate", "scheduledTime"],
12409
+ schedule = {}
12410
+ }) => {
12411
+ const matchUpScheduleKeys = Object.keys(schedule).filter((key) => scheduleAttributes.includes(key)).filter((key) => schedule[key]);
12412
+ return !!matchUpScheduleKeys.length;
12413
+ };
12414
+
11939
12415
  function participantScheduledMatchUps({
11940
12416
  scheduleAttributes = ["scheduledDate", "scheduledTime"],
11941
12417
  matchUps = []
@@ -12943,322 +13419,955 @@ function getTournamentParticipants(params) {
12943
13419
  })
12944
13420
  );
12945
13421
  }
12946
- return {
12947
- participantIdsWithConflicts,
12948
- tournamentParticipants,
12949
- eventsPublishStatuses
12950
- };
13422
+ return {
13423
+ participantIdsWithConflicts,
13424
+ tournamentParticipants,
13425
+ eventsPublishStatuses
13426
+ };
13427
+ }
13428
+
13429
+ function deepMerge(existing, incoming, arrayMerge) {
13430
+ if (!existing && incoming)
13431
+ return incoming;
13432
+ if (existing && !incoming)
13433
+ return existing;
13434
+ if (typeof existing !== "object" || typeof incoming !== "object")
13435
+ return existing;
13436
+ const keys = unique(Object.keys(existing).concat(Object.keys(incoming)));
13437
+ return keys.reduce((merged, key) => {
13438
+ if (!incoming[key]) {
13439
+ merged[key] = existing[key];
13440
+ } else if (!existing[key]) {
13441
+ merged[key] = incoming[key];
13442
+ } else if (typeof existing[key] !== typeof incoming[key]) {
13443
+ merged[key] = incoming[key];
13444
+ } else if (Array.isArray(existing[key])) {
13445
+ if (arrayMerge === true || Array.isArray(arrayMerge) && arrayMerge.includes(key)) {
13446
+ const mergedArrays = unique(
13447
+ existing[key].map((e) => JSON.stringify(e)).concat(incoming[key].map((i) => JSON.stringify(i)))
13448
+ ).map((u) => JSON.parse(u));
13449
+ merged[key] = mergedArrays;
13450
+ } else {
13451
+ merged[key] = incoming[key];
13452
+ }
13453
+ } else if (typeof existing[key] === "object") {
13454
+ merged[key] = deepMerge(existing[key], incoming[key], arrayMerge);
13455
+ } else {
13456
+ merged[key] = incoming[key];
13457
+ }
13458
+ return merged;
13459
+ }, {});
13460
+ }
13461
+
13462
+ function getCompetitionParticipants(params) {
13463
+ const { tournamentRecords } = params || {};
13464
+ if (typeof tournamentRecords !== "object" || !Object.keys(tournamentRecords).length)
13465
+ return { error: MISSING_TOURNAMENT_RECORDS };
13466
+ let competitionParticipants = [];
13467
+ const participantIdsWithConflicts = [];
13468
+ const competitionParticipantIds = [];
13469
+ for (const tournamentRecord of Object.values(tournamentRecords)) {
13470
+ const {
13471
+ tournamentParticipants,
13472
+ participantIdsWithConflicts: idsWithConflicts
13473
+ } = getTournamentParticipants({
13474
+ tournamentRecord,
13475
+ ...params
13476
+ });
13477
+ for (const tournamentParticipant of tournamentParticipants) {
13478
+ const { participantId } = tournamentParticipant;
13479
+ if (!competitionParticipantIds.includes(participantId)) {
13480
+ competitionParticipantIds.push(participantId);
13481
+ competitionParticipants.push(tournamentParticipant);
13482
+ } else {
13483
+ competitionParticipants = competitionParticipants.map(
13484
+ (participant) => participant.participantId !== participantId ? participant : deepMerge(participant, tournamentParticipant, true)
13485
+ );
13486
+ }
13487
+ }
13488
+ idsWithConflicts?.forEach((participantId) => {
13489
+ if (!participantIdsWithConflicts.includes(participantId))
13490
+ participantIdsWithConflicts.push(participantId);
13491
+ });
13492
+ }
13493
+ return { competitionParticipants, participantIdsWithConflicts, ...SUCCESS };
13494
+ }
13495
+ function publicFindParticipant({
13496
+ policyDefinitions,
13497
+ tournamentRecords,
13498
+ participantId,
13499
+ inContext,
13500
+ personId
13501
+ }) {
13502
+ if (!tournamentRecords)
13503
+ return { error: MISSING_TOURNAMENT_RECORDS };
13504
+ if (typeof participantId !== "string" && typeof personId !== "string")
13505
+ return { error: MISSING_VALUE, stack: "publicFindParticipant" };
13506
+ let participant, tournamentId;
13507
+ for (const tournamentRecord of Object.values(tournamentRecords)) {
13508
+ tournamentId = tournamentRecord.tournamentId;
13509
+ const { tournamentParticipants } = getTournamentParticipants({
13510
+ policyDefinitions,
13511
+ tournamentRecord,
13512
+ inContext
13513
+ });
13514
+ participant = findParticipant({
13515
+ tournamentParticipants,
13516
+ internalUse: true,
13517
+ policyDefinitions,
13518
+ participantId,
13519
+ personId
13520
+ });
13521
+ if (participant)
13522
+ break;
13523
+ }
13524
+ return { participant, tournamentId, ...SUCCESS };
13525
+ }
13526
+
13527
+ function getParticipantScaleItem({
13528
+ tournamentRecords,
13529
+ policyDefinitions,
13530
+ scaleAttributes,
13531
+ participantId,
13532
+ inContext,
13533
+ personId
13534
+ }) {
13535
+ let result = publicFindParticipant({
13536
+ tournamentRecords,
13537
+ policyDefinitions,
13538
+ participantId,
13539
+ inContext,
13540
+ personId
13541
+ });
13542
+ if (result.error)
13543
+ return result;
13544
+ const { participant, tournamentId } = result;
13545
+ result = participantScaleItem({ participant, scaleAttributes });
13546
+ if (result.error)
13547
+ return { ...result, tournamentId };
13548
+ return { ...SUCCESS, tournamentId, ...result };
13549
+ }
13550
+
13551
+ function getSourceStructureIdsAndRelevantLinks({
13552
+ targetRoundNumber,
13553
+ finishingPosition,
13554
+ drawDefinition,
13555
+ structureId,
13556
+ // structure for which source and target links are to be found
13557
+ linkType
13558
+ // only return links which match linkType
13559
+ }) {
13560
+ const { links } = getStructureLinks({
13561
+ drawDefinition,
13562
+ structureId
13563
+ }) || {};
13564
+ const sourceLinks = (links?.target || []).filter(({ linkType: structureLinkType }) => structureLinkType === linkType).filter(
13565
+ ({ target }) => !targetRoundNumber || targetRoundNumber === target.roundNumber
13566
+ );
13567
+ const relevantLinks = sourceLinks.map((link) => {
13568
+ const sourceStructureId = link.source.structureId;
13569
+ const { structure: sourceStructure } = findStructure({
13570
+ structureId: sourceStructureId,
13571
+ drawDefinition
13572
+ });
13573
+ if (finishingPosition && sourceStructure?.finishingPosition !== finishingPosition)
13574
+ return;
13575
+ return link;
13576
+ }).filter(Boolean);
13577
+ const sourceStructureIds = relevantLinks.map(
13578
+ ({ source }) => source.structureId
13579
+ );
13580
+ return { sourceStructureIds, relevantLinks };
13581
+ }
13582
+
13583
+ function getContainedStructures({
13584
+ tournamentRecord,
13585
+ drawDefinition,
13586
+ event
13587
+ }) {
13588
+ const events = tournamentRecord?.events || event && [event];
13589
+ const drawDefinitions = events?.map((event2) => event2?.drawDefinitions).flat().filter(Boolean) || drawDefinition && [drawDefinition] || [];
13590
+ const containedStructures = {};
13591
+ const containerStructures = {};
13592
+ const structureContainers = drawDefinitions.map((dd) => dd?.structures?.filter((structure) => structure?.structures)).flat().filter(Boolean);
13593
+ for (const structureContainer of structureContainers) {
13594
+ const { structures, structureId } = structureContainer || {};
13595
+ structures && structureId && (containedStructures[structureId] = structures?.map(
13596
+ (structure) => structure.structureId
13597
+ )) && structures.forEach(
13598
+ (structure) => containerStructures[structure.structureId] = structureContainer?.structureId
13599
+ );
13600
+ }
13601
+ return { containedStructures, containerStructures };
13602
+ }
13603
+
13604
+ function isActiveMatchUp({
13605
+ matchUpStatus,
13606
+ winningSide,
13607
+ tieMatchUps,
13608
+ sides,
13609
+ score
13610
+ }) {
13611
+ const participantAssigned = sides?.find(({ participantId }) => participantId);
13612
+ const activeTieMatchUps = tieMatchUps?.filter(isActiveMatchUp)?.length;
13613
+ const scoreExists = scoreHasValue({ score });
13614
+ return scoreExists || activeTieMatchUps || winningSide && participantAssigned || // if winningSide and no participant assigned => "produced" WALKOVER
13615
+ // must exclude IN_PROGRESS as this is automatically set by updateTieMatchUpScore
13616
+ // must exclude WALKOVER and DEFAULTED as "produced" scenarios do not imply a winningSide
13617
+ matchUpStatus && isActiveMatchUpStatus({ matchUpStatus }) && ![DEFAULTED, WALKOVER$1, IN_PROGRESS].includes(matchUpStatus);
13618
+ }
13619
+
13620
+ function getStructureDrawPositionProfiles(params) {
13621
+ const { drawDefinition, findContainer, structureId, event } = params;
13622
+ let structure = params.structure;
13623
+ const matchUpFilters = { isCollectionMatchUp: false };
13624
+ const { containedStructures } = getContainedStructures({ drawDefinition });
13625
+ const containedStructureIds = structureId ? containedStructures[structureId] || [] : [];
13626
+ if (!structure) {
13627
+ const result = findStructure({ drawDefinition, structureId });
13628
+ if (result.error)
13629
+ return result;
13630
+ structure = findContainer ? result.containingStructure || result.structure : result.structure;
13631
+ }
13632
+ if (isAdHoc({ drawDefinition, structure })) {
13633
+ return { structure, isAdHoc: true, error: INVALID_DRAW_POSITION };
13634
+ }
13635
+ const { matchUps: inContextDrawMatchUps } = getAllDrawMatchUps({
13636
+ inContext: true,
13637
+ matchUpFilters,
13638
+ drawDefinition,
13639
+ event
13640
+ });
13641
+ const inContextStructureMatchUps = inContextDrawMatchUps?.filter(
13642
+ (matchUp) => matchUp.structureId === structureId || containedStructureIds.includes(matchUp.structureId)
13643
+ );
13644
+ const { matchUpDependencies } = getMatchUpDependencies({
13645
+ drawIds: [drawDefinition.drawId],
13646
+ matchUps: inContextDrawMatchUps,
13647
+ drawDefinition
13648
+ });
13649
+ const activeDependentMatchUpIdsCollection = [];
13650
+ const drawPositionsCollection = [];
13651
+ const drawPositionInitialRounds = {};
13652
+ const activeMatchUps = [];
13653
+ for (const matchUp of inContextDrawMatchUps || []) {
13654
+ if (matchUp.structureId === structureId || containedStructureIds.includes(matchUp.structureId)) {
13655
+ drawPositionsCollection.push(...matchUp.drawPositions || []);
13656
+ const roundNumber = matchUp.roundNumber;
13657
+ for (const drawPosition of (matchUp.drawPositions || []).filter(
13658
+ Boolean
13659
+ )) {
13660
+ if (!drawPositionInitialRounds[drawPosition] || roundNumber && drawPositionInitialRounds[drawPosition] > roundNumber) {
13661
+ drawPositionInitialRounds[drawPosition] = roundNumber;
13662
+ }
13663
+ }
13664
+ }
13665
+ if (isActiveMatchUp(matchUp)) {
13666
+ activeMatchUps.push(matchUp);
13667
+ activeDependentMatchUpIdsCollection.push(
13668
+ matchUp.matchUpId,
13669
+ ...matchUpDependencies?.[matchUp?.matchUpId]?.matchUpIds || []
13670
+ );
13671
+ }
13672
+ }
13673
+ const drawPositions = unique(drawPositionsCollection.filter(Boolean)).sort(
13674
+ numericSort
13675
+ );
13676
+ const activeDependentMatchUpIds = unique(activeDependentMatchUpIdsCollection);
13677
+ const activeDrawPositions = unique(
13678
+ inContextStructureMatchUps?.map(
13679
+ ({ matchUpId, drawPositions: drawPositions2 }) => activeDependentMatchUpIds.includes(matchUpId) ? drawPositions2 : []
13680
+ ).flat().filter(Boolean)
13681
+ ).sort(numericSort);
13682
+ const { positionAssignments } = getPositionAssignments({
13683
+ drawDefinition,
13684
+ structure
13685
+ });
13686
+ const byeDrawPositions = positionAssignments?.filter((assignment) => assignment.bye).map((assignment) => assignment.drawPosition);
13687
+ const qualifyingDrawPositions = positionAssignments?.filter((assignment) => assignment.qualifier).map((assignment) => assignment.drawPosition);
13688
+ const inactiveDrawPositions = drawPositions?.filter(
13689
+ (drawPosition) => !activeDrawPositions.includes(drawPosition)
13690
+ ) || [];
13691
+ return {
13692
+ allDrawPositions: drawPositions,
13693
+ inContextStructureMatchUps,
13694
+ drawPositionInitialRounds,
13695
+ activeDependentMatchUpIds,
13696
+ qualifyingDrawPositions,
13697
+ inactiveDrawPositions,
13698
+ positionAssignments,
13699
+ activeDrawPositions,
13700
+ byeDrawPositions,
13701
+ activeMatchUps,
13702
+ structure
13703
+ };
13704
+ }
13705
+
13706
+ function getAssignedParticipantIds({
13707
+ drawDefinition,
13708
+ stages
13709
+ }) {
13710
+ const stageStructures = (drawDefinition?.structures || []).filter(
13711
+ (structure) => !stages?.length || structure.stage && stages.includes(structure.stage)
13712
+ );
13713
+ return stageStructures.map((structure) => {
13714
+ const { positionAssignments } = getPositionAssignments({
13715
+ structure
13716
+ });
13717
+ return positionAssignments ? positionAssignments.map(extractAttributes("participantId")) : [];
13718
+ }).flat();
13719
+ }
13720
+
13721
+ function getValidModifyAssignedPairAction({
13722
+ tournamentParticipants,
13723
+ returnParticipants,
13724
+ drawPosition,
13725
+ participant,
13726
+ drawId,
13727
+ event
13728
+ }) {
13729
+ const availableIndividualParticipantIds = event?.entries?.filter(({ entryStatus }) => [UNGROUPED, UNPAIRED].includes(entryStatus)).map(({ participantId }) => participantId) || [];
13730
+ if (availableIndividualParticipantIds.length) {
13731
+ const existingIndividualParticipantIds = participant.individualParticipantIds;
13732
+ const availableIndividualParticipants = returnParticipants ? tournamentParticipants.filter(
13733
+ ({ participantId }) => availableIndividualParticipantIds.includes(participantId)
13734
+ ) : void 0;
13735
+ const existingIndividualParticipants = returnParticipants ? tournamentParticipants.filter(
13736
+ ({ participantId }) => existingIndividualParticipantIds.includes(participantId)
13737
+ ) : void 0;
13738
+ const validModifyAssignedPairAction = definedAttributes(
13739
+ {
13740
+ payload: {
13741
+ participantId: participant.participantId,
13742
+ replacementIndividualParticipantId: void 0,
13743
+ existingIndividualParticipantId: void 0,
13744
+ drawPosition,
13745
+ drawId
13746
+ },
13747
+ method: MODIFY_PAIR_ASSIGNMENT_METHOD,
13748
+ availableIndividualParticipantIds,
13749
+ availableIndividualParticipants,
13750
+ existingIndividualParticipantIds,
13751
+ existingIndividualParticipants,
13752
+ type: MODIFY_PAIR_ASSIGNMENT
13753
+ },
13754
+ false,
13755
+ false,
13756
+ true
13757
+ );
13758
+ return { validModifyAssignedPairAction };
13759
+ }
13760
+ return {};
13761
+ }
13762
+
13763
+ function getInitialRoundNumber({
13764
+ drawPosition,
13765
+ matchUps = []
13766
+ }) {
13767
+ const initialRoundNumber = matchUps.filter(
13768
+ ({ drawPositions }) => drawPosition && drawPositions?.includes(drawPosition)
13769
+ ).map(({ roundNumber }) => roundNumber).sort(numericSort)[0];
13770
+ return { initialRoundNumber };
13771
+ }
13772
+
13773
+ function getValidLuckyLosersAction({
13774
+ tournamentParticipants = [],
13775
+ sourceStructuresComplete,
13776
+ possiblyDisablingAction,
13777
+ isWinRatioFedStructure,
13778
+ activeDrawPositions,
13779
+ positionAssignments,
13780
+ drawDefinition,
13781
+ drawPosition,
13782
+ structureId,
13783
+ structure,
13784
+ drawId,
13785
+ event
13786
+ }) {
13787
+ if (activeDrawPositions.includes(drawPosition) || // can't be a lucky loser if still have matches to play in a round robin structure!!
13788
+ isWinRatioFedStructure && !sourceStructuresComplete) {
13789
+ return {};
13790
+ }
13791
+ const { sourceStructureIds, targetStructureIds } = drawDefinition.links?.reduce(
13792
+ (ids, link) => {
13793
+ const sourceStructureId = link.source?.structureId;
13794
+ const targetStructureId = link.target?.structureId;
13795
+ if (!ids.sourceStructureIds.includes(sourceStructureId))
13796
+ ids.sourceStructureIds.push(sourceStructureId);
13797
+ if (!ids.targetStructureIds.includes(targetStructureId))
13798
+ ids.targetStructureIds.push(targetStructureId);
13799
+ return ids;
13800
+ },
13801
+ { sourceStructureIds: [], targetStructureIds: [] }
13802
+ ) || {};
13803
+ const availableLuckyLoserParticipantIds = [];
13804
+ const relevantLinks = drawDefinition.links?.filter(
13805
+ (link) => link.target?.structureId === structure.structureId
13806
+ ) || [];
13807
+ for (const relevantLink of relevantLinks) {
13808
+ const sourceStructureId = relevantLink?.source?.structureId;
13809
+ const { structure: sourceStructure } = findStructure({
13810
+ structureId: sourceStructureId,
13811
+ drawDefinition
13812
+ });
13813
+ const restrictBySourceRound = sourceStructure?.finishingPosition === ROUND_OUTCOME && (sourceStructureIds?.length !== 1 || targetStructureIds?.length !== 1);
13814
+ const matchUpFilters = {};
13815
+ if (restrictBySourceRound) {
13816
+ const { matchUps } = getAllStructureMatchUps({
13817
+ drawDefinition,
13818
+ structure,
13819
+ event
13820
+ });
13821
+ const { initialRoundNumber } = getInitialRoundNumber({
13822
+ drawPosition,
13823
+ matchUps
13824
+ });
13825
+ const relevantLink2 = drawDefinition.links?.find(
13826
+ (link) => link.target?.structureId === structure?.structureId && link.target.roundNumber === initialRoundNumber
13827
+ );
13828
+ const sourceRoundNumber = relevantLink2?.source?.roundNumber;
13829
+ matchUpFilters.roundNumbers = [sourceRoundNumber];
13830
+ }
13831
+ const { completedMatchUps } = getStructureMatchUps({
13832
+ structureId: sourceStructureId,
13833
+ inContext: true,
13834
+ matchUpFilters,
13835
+ drawDefinition
13836
+ });
13837
+ const assignedParticipantIds = positionAssignments.map((assignment) => assignment.participantId).filter(Boolean);
13838
+ const availableParticipantIds = completedMatchUps?.filter(
13839
+ ({ matchUpType, winningSide }) => winningSide && (event?.eventType !== TEAM || matchUpType === TEAM)
13840
+ ).map(
13841
+ ({ winningSide, sides }) => winningSide && sides?.[1 - (winningSide - 1)]
13842
+ ).map(extractAttributes("participantId")).filter(
13843
+ (participantId) => participantId && !assignedParticipantIds.includes(participantId)
13844
+ );
13845
+ availableParticipantIds?.forEach((participantId) => {
13846
+ if (!availableLuckyLoserParticipantIds.includes(participantId))
13847
+ availableLuckyLoserParticipantIds.push(participantId);
13848
+ });
13849
+ }
13850
+ const availableLuckyLosers = tournamentParticipants?.filter(
13851
+ (participant) => availableLuckyLoserParticipantIds?.includes(participant.participantId)
13852
+ );
13853
+ availableLuckyLosers?.forEach((luckyLoser) => {
13854
+ const entry = (drawDefinition.entries || []).find(
13855
+ (entry2) => entry2.participantId === luckyLoser.participantId
13856
+ );
13857
+ luckyLoser.entryPosition = entry?.entryPosition;
13858
+ });
13859
+ if (availableLuckyLoserParticipantIds?.length) {
13860
+ const validLuckyLosersAction = {
13861
+ type: LUCKY_PARTICIPANT,
13862
+ method: LUCKY_PARTICIPANT_METHOD,
13863
+ availableLuckyLosers,
13864
+ availableLuckyLoserParticipantIds,
13865
+ willDisableLinks: possiblyDisablingAction,
13866
+ payload: { drawId, structureId, drawPosition }
13867
+ };
13868
+ return { validLuckyLosersAction };
13869
+ }
13870
+ return {};
12951
13871
  }
12952
13872
 
12953
- function deepMerge(existing, incoming, arrayMerge) {
12954
- if (!existing && incoming)
12955
- return incoming;
12956
- if (existing && !incoming)
12957
- return existing;
12958
- if (typeof existing !== "object" || typeof incoming !== "object")
12959
- return existing;
12960
- const keys = unique(Object.keys(existing).concat(Object.keys(incoming)));
12961
- return keys.reduce((merged, key) => {
12962
- if (!incoming[key]) {
12963
- merged[key] = existing[key];
12964
- } else if (!existing[key]) {
12965
- merged[key] = incoming[key];
12966
- } else if (typeof existing[key] !== typeof incoming[key]) {
12967
- merged[key] = incoming[key];
12968
- } else if (Array.isArray(existing[key])) {
12969
- if (arrayMerge === true || Array.isArray(arrayMerge) && arrayMerge.includes(key)) {
12970
- const mergedArrays = unique(
12971
- existing[key].map((e) => JSON.stringify(e)).concat(incoming[key].map((i) => JSON.stringify(i)))
12972
- ).map((u) => JSON.parse(u));
12973
- merged[key] = mergedArrays;
12974
- } else {
12975
- merged[key] = incoming[key];
12976
- }
12977
- } else if (typeof existing[key] === "object") {
12978
- merged[key] = deepMerge(existing[key], incoming[key], arrayMerge);
12979
- } else {
12980
- merged[key] = incoming[key];
13873
+ function getNumericSeedValue(seedValue) {
13874
+ if (!seedValue)
13875
+ return Infinity;
13876
+ if (isConvertableInteger(seedValue))
13877
+ return ensureInt(seedValue);
13878
+ const firstValue = seedValue.split("-")[0];
13879
+ if (isConvertableInteger(firstValue))
13880
+ return ensureInt(firstValue);
13881
+ return Infinity;
13882
+ }
13883
+
13884
+ function getValidGroupSizes({
13885
+ drawSize,
13886
+ groupSizeLimit = 10
13887
+ }) {
13888
+ const validGroupSizes = generateRange(3, groupSizeLimit + 1).filter(
13889
+ (groupSize) => {
13890
+ const groupsCount = Math.ceil(drawSize / groupSize);
13891
+ const byesCount = groupsCount * groupSize - drawSize;
13892
+ const maxParticipantsPerGroup = Math.ceil(drawSize / groupsCount);
13893
+ const maxByesPerGroup = Math.ceil(byesCount / groupsCount);
13894
+ return (!byesCount || byesCount < groupSize) && maxParticipantsPerGroup === groupSize && maxParticipantsPerGroup >= 3 && maxByesPerGroup < 2;
12981
13895
  }
12982
- return merged;
12983
- }, {});
13896
+ );
13897
+ return { ...SUCCESS, validGroupSizes };
12984
13898
  }
12985
13899
 
12986
- function getCompetitionParticipants(params) {
12987
- const { tournamentRecords } = params || {};
12988
- if (typeof tournamentRecords !== "object" || !Object.keys(tournamentRecords).length)
12989
- return { error: MISSING_TOURNAMENT_RECORDS };
12990
- let competitionParticipants = [];
12991
- const participantIdsWithConflicts = [];
12992
- const competitionParticipantIds = [];
12993
- for (const tournamentRecord of Object.values(tournamentRecords)) {
12994
- const {
12995
- tournamentParticipants,
12996
- participantIdsWithConflicts: idsWithConflicts
12997
- } = getTournamentParticipants({
12998
- tournamentRecord,
12999
- ...params
13900
+ function getSeedBlocks(params) {
13901
+ const { roundRobinGroupsCount, participantsCount, cluster } = params;
13902
+ if (!isConvertableInteger(participantsCount))
13903
+ return {
13904
+ seedBlocks: void 0,
13905
+ ...decorateResult({
13906
+ result: { error: INVALID_VALUES },
13907
+ context: { participantsCount },
13908
+ stack: "getSeedBlocks"
13909
+ })
13910
+ };
13911
+ const drawSize = nextPowerOf2(participantsCount);
13912
+ if (roundRobinGroupsCount) {
13913
+ const increment = Math.min(roundRobinGroupsCount, drawSize);
13914
+ const seedBlocks2 = [];
13915
+ let position = 1;
13916
+ generateRange(0, increment).forEach(() => {
13917
+ seedBlocks2.push([position]);
13918
+ position++;
13000
13919
  });
13001
- for (const tournamentParticipant of tournamentParticipants) {
13002
- const { participantId } = tournamentParticipant;
13003
- if (!competitionParticipantIds.includes(participantId)) {
13004
- competitionParticipantIds.push(participantId);
13005
- competitionParticipants.push(tournamentParticipant);
13920
+ while (position < drawSize) {
13921
+ const range2 = generateRange(position, position + increment);
13922
+ position += increment;
13923
+ seedBlocks2.push(range2);
13924
+ }
13925
+ return { ...SUCCESS, seedBlocks: seedBlocks2 };
13926
+ }
13927
+ const range = generateRange(1, drawSize + 1);
13928
+ const positions = [];
13929
+ let chunkSize = drawSize / 2;
13930
+ while (chunkSize > 1) {
13931
+ const chunks = chunkArray(range, chunkSize);
13932
+ const chunksCount = chunks.length;
13933
+ chunks.forEach((chunk, i) => {
13934
+ let candidate;
13935
+ const top = i < chunksCount / 2;
13936
+ const isEven = i % 2 === 0;
13937
+ const first = chunk[0];
13938
+ const last = chunk[chunk.length - 1];
13939
+ if (cluster && chunksCount > 4) {
13940
+ if (chunksCount === 8) {
13941
+ candidate = top ? last : first;
13942
+ } else {
13943
+ candidate = isEven ? first : last;
13944
+ }
13006
13945
  } else {
13007
- competitionParticipants = competitionParticipants.map(
13008
- (participant) => participant.participantId !== participantId ? participant : deepMerge(participant, tournamentParticipant, true)
13009
- );
13946
+ candidate = top ? first : last;
13947
+ }
13948
+ if (!overlap(chunk, positions)) {
13949
+ positions.push(candidate);
13010
13950
  }
13011
- }
13012
- idsWithConflicts?.forEach((participantId) => {
13013
- if (!participantIdsWithConflicts.includes(participantId))
13014
- participantIdsWithConflicts.push(participantId);
13015
13951
  });
13952
+ chunkSize = chunkSize / 2;
13016
13953
  }
13017
- return { competitionParticipants, participantIdsWithConflicts, ...SUCCESS };
13018
- }
13019
- function publicFindParticipant({
13020
- policyDefinitions,
13021
- tournamentRecords,
13022
- participantId,
13023
- inContext,
13024
- personId
13025
- }) {
13026
- if (!tournamentRecords)
13027
- return { error: MISSING_TOURNAMENT_RECORDS };
13028
- if (typeof participantId !== "string" && typeof personId !== "string")
13029
- return { error: MISSING_VALUE, stack: "publicFindParticipant" };
13030
- let participant, tournamentId;
13031
- for (const tournamentRecord of Object.values(tournamentRecords)) {
13032
- tournamentId = tournamentRecord.tournamentId;
13033
- const { tournamentParticipants } = getTournamentParticipants({
13034
- policyDefinitions,
13035
- tournamentRecord,
13036
- inContext
13037
- });
13038
- participant = findParticipant({
13039
- tournamentParticipants,
13040
- internalUse: true,
13041
- policyDefinitions,
13042
- participantId,
13043
- personId
13044
- });
13045
- if (participant)
13046
- break;
13954
+ const remainingPositions = range.filter(
13955
+ (position) => !positions.includes(position)
13956
+ );
13957
+ while (remainingPositions.length) {
13958
+ if (remainingPositions.length % 2 === 0) {
13959
+ positions.push(remainingPositions.pop());
13960
+ } else {
13961
+ positions.push(remainingPositions.shift());
13962
+ }
13047
13963
  }
13048
- return { participant, tournamentId, ...SUCCESS };
13964
+ const seedBlockSizes = generateRange(0, 20).map((x) => Math.pow(2, x));
13965
+ seedBlockSizes.unshift(1);
13966
+ const iterations = seedBlockSizes.indexOf(drawSize);
13967
+ let sum = 0;
13968
+ const seedBlocks = [];
13969
+ generateRange(0, iterations).forEach((i) => {
13970
+ seedBlocks.push(positions.slice(sum, sum + seedBlockSizes[i]));
13971
+ sum += seedBlockSizes[i];
13972
+ });
13973
+ return { ...SUCCESS, seedBlocks };
13049
13974
  }
13050
-
13051
- function getParticipantScaleItem({
13052
- tournamentRecords,
13053
- policyDefinitions,
13054
- scaleAttributes,
13055
- participantId,
13056
- inContext,
13057
- personId
13975
+ function getSeedGroups({
13976
+ roundRobinGroupsCount,
13977
+ drawSize
13058
13978
  }) {
13059
- let result = publicFindParticipant({
13060
- tournamentRecords,
13061
- policyDefinitions,
13062
- participantId,
13063
- inContext,
13064
- personId
13065
- });
13066
- if (result.error)
13067
- return result;
13068
- const { participant, tournamentId } = result;
13069
- result = participantScaleItem({ participant, scaleAttributes });
13070
- if (result.error)
13071
- return { ...result, tournamentId };
13072
- return { ...SUCCESS, tournamentId, ...result };
13979
+ const stack = "getSeedGroups";
13980
+ if (!isConvertableInteger(drawSize))
13981
+ return {
13982
+ seedGroups: void 0,
13983
+ ...decorateResult({
13984
+ result: { error: INVALID_VALUES },
13985
+ context: { drawSize },
13986
+ stack
13987
+ })
13988
+ };
13989
+ if (roundRobinGroupsCount) {
13990
+ if (!isConvertableInteger(roundRobinGroupsCount))
13991
+ return {
13992
+ seedGroups: void 0,
13993
+ ...decorateResult({
13994
+ context: { roundRobinGroupsCount },
13995
+ result: { error: INVALID_VALUES },
13996
+ stack
13997
+ })
13998
+ };
13999
+ let seedNumber = 1;
14000
+ const roundsCount = Math.floor(drawSize / roundRobinGroupsCount);
14001
+ const seedGroups = generateRange(0, roundsCount).map(() => {
14002
+ const seedNumbers = generateRange(
14003
+ seedNumber,
14004
+ seedNumber + roundRobinGroupsCount
14005
+ );
14006
+ seedNumber += roundRobinGroupsCount;
14007
+ return seedNumbers;
14008
+ });
14009
+ return { seedGroups };
14010
+ } else {
14011
+ const { seedBlocks } = getSeedBlocks({
14012
+ participantsCount: drawSize,
14013
+ roundRobinGroupsCount
14014
+ });
14015
+ let seedNumber = 0;
14016
+ const seedGroups = (seedBlocks || []).map(
14017
+ (seedBlock) => (seedBlock || []).map(() => {
14018
+ seedNumber += 1;
14019
+ return seedNumber;
14020
+ })
14021
+ );
14022
+ return { seedGroups };
14023
+ }
13073
14024
  }
13074
14025
 
13075
- function getSourceStructureIdsAndRelevantLinks({
13076
- targetRoundNumber,
13077
- finishingPosition,
14026
+ function getValidSeedBlocks({
14027
+ provisionalPositioning,
14028
+ appliedPolicies,
13078
14029
  drawDefinition,
13079
- structureId,
13080
- // structure for which source and target links are to be found
13081
- linkType
13082
- // only return links which match linkType
14030
+ allPositions,
14031
+ structure
13083
14032
  }) {
13084
- const { links } = getStructureLinks({
14033
+ let validSeedBlocks = [];
14034
+ if (!structure)
14035
+ return { error: MISSING_STRUCTURE };
14036
+ const { matchUps, roundMatchUps } = getAllStructureMatchUps({
14037
+ matchUpFilters: { roundNumbers: [1] },
14038
+ provisionalPositioning,
14039
+ structure
14040
+ });
14041
+ const { seedAssignments } = getStructureSeedAssignments({
14042
+ provisionalPositioning,
13085
14043
  drawDefinition,
13086
- structureId
13087
- }) || {};
13088
- const sourceLinks = (links?.target || []).filter(({ linkType: structureLinkType }) => structureLinkType === linkType).filter(
13089
- ({ target }) => !targetRoundNumber || targetRoundNumber === target.roundNumber
14044
+ structure
14045
+ });
14046
+ const { positionAssignments } = structureAssignedDrawPositions({ structure });
14047
+ const positionsCount = positionAssignments?.length;
14048
+ const seedsCount = seedAssignments?.length ?? 0;
14049
+ let allDrawPositions = [];
14050
+ const roundNumbers = Object.keys(roundMatchUps).map((n) => parseInt(n)).sort((a, b) => a - b);
14051
+ const uniqueDrawPositionsByRound = roundNumbers.map((roundNumber) => {
14052
+ const roundDrawPositions = roundMatchUps[roundNumber].map((matchUp) => matchUp.drawPositions).flat(Infinity).filter(Boolean);
14053
+ const uniqueRoundDrawPositions = roundDrawPositions.filter(
14054
+ (drawPosition) => !allDrawPositions.includes(drawPosition)
14055
+ );
14056
+ allDrawPositions = allDrawPositions.concat(...roundDrawPositions);
14057
+ return uniqueRoundDrawPositions;
14058
+ }).filter((f) => f.length).reverse();
14059
+ const firstRoundDrawPositions = uniqueDrawPositionsByRound.pop();
14060
+ const firstRoundDrawPositionOffset = firstRoundDrawPositions && Math.min(...firstRoundDrawPositions) - 1 || 0;
14061
+ const seedingProfile = appliedPolicies?.seeding?.seedingProfile;
14062
+ const baseDrawSize = firstRoundDrawPositions?.length || 0;
14063
+ const seedRangeDrawPositionBlocks = uniqueDrawPositionsByRound.filter(
14064
+ (block) => block.filter((drawPosition) => drawPosition <= seedsCount).length
13090
14065
  );
13091
- const relevantLinks = sourceLinks.map((link) => {
13092
- const sourceStructureId = link.source.structureId;
13093
- const { structure: sourceStructure } = findStructure({
13094
- structureId: sourceStructureId,
13095
- drawDefinition
14066
+ const { stage, structureType, roundLimit } = structure;
14067
+ const isContainer = structureType === CONTAINER;
14068
+ const isFeedIn = !isContainer && uniqueDrawPositionsByRound?.length;
14069
+ const qualifyingBlocks = !isContainer && stage === QUALIFYING && roundLimit;
14070
+ const fedSeedBlockPositions = seedRangeDrawPositionBlocks.flat(Infinity);
14071
+ const fedSeedNumberOffset = isFeedIn ? fedSeedBlockPositions?.length : 0;
14072
+ const countLimit = allPositions ? positionsCount : seedsCount;
14073
+ const isLuckyStructure = isLucky({
14074
+ drawDefinition,
14075
+ structure,
14076
+ matchUps
14077
+ });
14078
+ const firstRoundSeedsCount = isLuckyStructure ? 0 : !isFeedIn && countLimit || countLimit && fedSeedBlockPositions.length < countLimit && countLimit - fedSeedBlockPositions.length || 0;
14079
+ if (qualifyingBlocks) {
14080
+ const seedingBlocksCount = structure?.matchUps ? structure.matchUps.filter(
14081
+ ({ roundNumber }) => roundNumber === structure.roundLimit
14082
+ ).length : 0;
14083
+ const chunkSize = firstRoundDrawPositions.length / seedingBlocksCount;
14084
+ if (isFeedIn) ; else {
14085
+ const positioning = getSeedPattern(seedingProfile);
14086
+ const drawPositionChunks = chunkArray(firstRoundDrawPositions, chunkSize);
14087
+ let groupNumber = 1;
14088
+ const seedGroups = generateRange(0, drawPositionChunks[0].length).map(
14089
+ () => {
14090
+ const seedNumbers = generateRange(
14091
+ groupNumber,
14092
+ groupNumber + drawPositionChunks.length
14093
+ );
14094
+ groupNumber += drawPositionChunks.length;
14095
+ return seedNumbers;
14096
+ }
14097
+ );
14098
+ ({ validSeedBlocks } = getSeedBlockPattern({
14099
+ drawPositionBlocks: drawPositionChunks,
14100
+ positioning,
14101
+ seedGroups
14102
+ }));
14103
+ }
14104
+ } else if (isContainer) {
14105
+ const result = getContainerBlocks({
14106
+ seedingProfile,
14107
+ structure
13096
14108
  });
13097
- if (finishingPosition && sourceStructure?.finishingPosition !== finishingPosition)
13098
- return;
13099
- return link;
13100
- }).filter(Boolean);
13101
- const sourceStructureIds = relevantLinks.map(
13102
- ({ source }) => source.structureId
14109
+ ({ validSeedBlocks } = result);
14110
+ } else if (isFeedIn) {
14111
+ validSeedBlocks = seedRangeDrawPositionBlocks.map((block) => {
14112
+ return { seedNumbers: block, drawPositions: block };
14113
+ });
14114
+ } else if (isLuckyStructure) {
14115
+ const blocks = chunkArray(firstRoundDrawPositions, 2).map((block, i) => ({
14116
+ drawPositions: [block[0]],
14117
+ seedNumbers: [i + 1]
14118
+ }));
14119
+ blocks.forEach((block) => validSeedBlocks.push(block));
14120
+ }
14121
+ if (!isContainer && !isLuckyStructure && !qualifyingBlocks) {
14122
+ const { blocks } = constructPower2Blocks({
14123
+ drawPositionOffset: firstRoundDrawPositionOffset,
14124
+ seedNumberOffset: fedSeedNumberOffset,
14125
+ seedCountGoal: firstRoundSeedsCount,
14126
+ seedingProfile,
14127
+ baseDrawSize
14128
+ });
14129
+ blocks.forEach((block) => validSeedBlocks.push(block));
14130
+ }
14131
+ const seedDrawPositions = validSeedBlocks.flatMap(
14132
+ (seedBlock) => seedBlock.drawPositions
13103
14133
  );
13104
- return { sourceStructureIds, relevantLinks };
14134
+ const validSeedPositions = seedDrawPositions.reduce(
14135
+ (result, drawPosition) => {
14136
+ return firstRoundDrawPositions?.includes(drawPosition) && result;
14137
+ },
14138
+ true
14139
+ );
14140
+ if (!isLuckyStructure && !isFeedIn && !isContainer && !validSeedPositions) {
14141
+ return {
14142
+ error: INVALID_SEED_POSITION,
14143
+ validSeedBlocks: [],
14144
+ isContainer,
14145
+ isFeedIn
14146
+ };
14147
+ }
14148
+ return {
14149
+ isLuckyStructure,
14150
+ validSeedBlocks,
14151
+ isContainer,
14152
+ isFeedIn
14153
+ };
13105
14154
  }
13106
-
13107
- function getAssignedParticipantIds({
13108
- drawDefinition,
13109
- stages
13110
- }) {
13111
- const stageStructures = (drawDefinition?.structures || []).filter(
13112
- (structure) => !stages?.length || structure.stage && stages.includes(structure.stage)
14155
+ function getContainerBlocks({ seedingProfile, structure }) {
14156
+ const containedStructures = structure.structures || [];
14157
+ const roundRobinGroupsCount = containedStructures.length;
14158
+ const positionAssignments = getPositionAssignments({
14159
+ structure
14160
+ })?.positionAssignments;
14161
+ const positioning = getSeedPattern(seedingProfile);
14162
+ const drawSize = positionAssignments?.length ?? 0;
14163
+ const { seedGroups } = getSeedGroups({
14164
+ roundRobinGroupsCount,
14165
+ drawSize
14166
+ });
14167
+ const drawPositionBlocks = containedStructures.map(
14168
+ (containedStructure) => getPositionAssignments({
14169
+ structure: containedStructure
14170
+ }).positionAssignments?.map((assignment) => assignment.drawPosition)
13113
14171
  );
13114
- return stageStructures.map((structure) => {
13115
- const { positionAssignments } = getPositionAssignments({
13116
- structure
14172
+ return getSeedBlockPattern({
14173
+ drawPositionBlocks,
14174
+ positioning,
14175
+ seedGroups
14176
+ });
14177
+ }
14178
+ function getSeedBlockPattern({ positioning, seedGroups, drawPositionBlocks }) {
14179
+ const validSeedBlocks = [];
14180
+ const topDown = (a, b) => a - b;
14181
+ const bottomUp = (a, b) => b - a;
14182
+ const assignedPositions = [];
14183
+ seedGroups.forEach((seedGroup, i) => {
14184
+ if (i && positioning !== WATERFALL) {
14185
+ shuffleArray(seedGroup);
14186
+ }
14187
+ seedGroup.forEach((seedNumber, j) => {
14188
+ const blockIndex = i % 2 ? drawPositionBlocks.length - j - 1 : j;
14189
+ const drawPosition = drawPositionBlocks[blockIndex].sort(i % 2 ? bottomUp : topDown).find((drawPosition2) => !assignedPositions.includes(drawPosition2));
14190
+ assignedPositions.push(drawPosition);
14191
+ validSeedBlocks.push({
14192
+ seedNumbers: [seedNumber],
14193
+ drawPositions: [drawPosition]
14194
+ });
13117
14195
  });
13118
- return positionAssignments ? positionAssignments.map(extractAttributes("participantId")) : [];
13119
- }).flat();
14196
+ });
14197
+ return { validSeedBlocks };
13120
14198
  }
13121
-
13122
- function getValidModifyAssignedPairAction({
13123
- tournamentParticipants,
13124
- returnParticipants,
13125
- drawPosition,
13126
- participant,
13127
- drawId,
13128
- event
13129
- }) {
13130
- const availableIndividualParticipantIds = event?.entries?.filter(({ entryStatus }) => [UNGROUPED, UNPAIRED].includes(entryStatus)).map(({ participantId }) => participantId) || [];
13131
- if (availableIndividualParticipantIds.length) {
13132
- const existingIndividualParticipantIds = participant.individualParticipantIds;
13133
- const availableIndividualParticipants = returnParticipants ? tournamentParticipants.filter(
13134
- ({ participantId }) => availableIndividualParticipantIds.includes(participantId)
13135
- ) : void 0;
13136
- const existingIndividualParticipants = returnParticipants ? tournamentParticipants.filter(
13137
- ({ participantId }) => existingIndividualParticipantIds.includes(participantId)
13138
- ) : void 0;
13139
- const validModifyAssignedPairAction = definedAttributes(
13140
- {
13141
- payload: {
13142
- participantId: participant.participantId,
13143
- replacementIndividualParticipantId: void 0,
13144
- existingIndividualParticipantId: void 0,
13145
- drawPosition,
13146
- drawId
13147
- },
13148
- method: MODIFY_PAIR_ASSIGNMENT_METHOD,
13149
- availableIndividualParticipantIds,
13150
- availableIndividualParticipants,
13151
- existingIndividualParticipantIds,
13152
- existingIndividualParticipants,
13153
- type: MODIFY_PAIR_ASSIGNMENT
13154
- },
13155
- false,
13156
- false,
13157
- true
14199
+ function constructPower2Blocks(params) {
14200
+ const {
14201
+ drawPositionOffset = 0,
14202
+ roundRobinGroupsCount,
14203
+ seedNumberOffset = 0,
14204
+ seedingProfile,
14205
+ seedCountGoal,
14206
+ baseDrawSize
14207
+ } = params;
14208
+ let count = 1;
14209
+ const blocks = [];
14210
+ const { seedBlocks } = getSeedBlocks({
14211
+ cluster: getSeedPattern(seedingProfile) === CLUSTER,
14212
+ participantsCount: baseDrawSize,
14213
+ roundRobinGroupsCount
14214
+ });
14215
+ count = 0;
14216
+ for (const seedBlock of seedBlocks) {
14217
+ if (count + 1 > seedCountGoal)
14218
+ break;
14219
+ const drawPositions = seedBlock.map(
14220
+ (drawPosition) => drawPosition + drawPositionOffset
13158
14221
  );
13159
- return { validModifyAssignedPairAction };
14222
+ const seedNumbers = getSeeds(count + 1, seedBlock.length).map(
14223
+ (seedNumber) => +seedNumber + seedNumberOffset
14224
+ );
14225
+ count += seedBlock.length;
14226
+ blocks.push({ drawPositions, seedNumbers });
14227
+ }
14228
+ return { blocks };
14229
+ function getSeeds(s, n) {
14230
+ return Array.from(new Array(n), (_, i) => i + s);
13160
14231
  }
13161
- return {};
13162
14232
  }
13163
-
13164
- function getValidLuckyLosersAction({
13165
- tournamentParticipants = [],
13166
- sourceStructuresComplete,
13167
- possiblyDisablingAction,
13168
- isWinRatioFedStructure,
13169
- activeDrawPositions,
13170
- positionAssignments,
14233
+ function isValidSeedPosition({
14234
+ appliedPolicies,
13171
14235
  drawDefinition,
14236
+ seedBlockInfo,
13172
14237
  drawPosition,
13173
14238
  structureId,
13174
- structure,
13175
- drawId,
13176
- event
14239
+ seedNumber
13177
14240
  }) {
13178
- if (activeDrawPositions.includes(drawPosition) || // can't be a lucky loser if still have matches to play in a round robin structure!!
13179
- isWinRatioFedStructure && !sourceStructuresComplete) {
13180
- return {};
14241
+ const { structure } = findStructure({ drawDefinition, structureId });
14242
+ if (!appliedPolicies) {
14243
+ appliedPolicies = getAppliedPolicies({ drawDefinition }).appliedPolicies;
13181
14244
  }
13182
- const { sourceStructureIds, targetStructureIds } = drawDefinition.links?.reduce(
13183
- (ids, link) => {
13184
- const sourceStructureId = link.source?.structureId;
13185
- const targetStructureId = link.target?.structureId;
13186
- if (!ids.sourceStructureIds.includes(sourceStructureId))
13187
- ids.sourceStructureIds.push(sourceStructureId);
13188
- if (!ids.targetStructureIds.includes(targetStructureId))
13189
- ids.targetStructureIds.push(targetStructureId);
13190
- return ids;
13191
- },
13192
- { sourceStructureIds: [], targetStructureIds: [] }
13193
- ) || {};
13194
- const availableLuckyLoserParticipantIds = [];
13195
- const relevantLinks = drawDefinition.links?.filter(
13196
- (link) => link.target?.structureId === structure.structureId
13197
- ) || [];
13198
- for (const relevantLink of relevantLinks) {
13199
- const sourceStructureId = relevantLink?.source?.structureId;
13200
- const { structure: sourceStructure } = findStructure({
13201
- structureId: sourceStructureId,
13202
- drawDefinition
13203
- });
13204
- const restrictBySourceRound = sourceStructure?.finishingPosition === ROUND_OUTCOME && (sourceStructureIds?.length !== 1 || targetStructureIds?.length !== 1);
13205
- const matchUpFilters = {};
13206
- if (restrictBySourceRound) {
13207
- const { matchUps } = getAllStructureMatchUps({
13208
- drawDefinition,
13209
- structure,
13210
- event
13211
- });
13212
- const { initialRoundNumber } = getInitialRoundNumber({
13213
- drawPosition,
13214
- matchUps
13215
- });
13216
- const relevantLink2 = drawDefinition.links?.find(
13217
- (link) => link.target?.structureId === structure?.structureId && link.target.roundNumber === initialRoundNumber
13218
- );
13219
- const sourceRoundNumber = relevantLink2?.source?.roundNumber;
13220
- matchUpFilters.roundNumbers = [sourceRoundNumber];
13221
- }
13222
- const { completedMatchUps } = getStructureMatchUps({
13223
- structureId: sourceStructureId,
13224
- inContext: true,
13225
- matchUpFilters,
13226
- drawDefinition
13227
- });
13228
- const assignedParticipantIds = positionAssignments.map((assignment) => assignment.participantId).filter(Boolean);
13229
- const availableParticipantIds = completedMatchUps?.filter(
13230
- ({ matchUpType, winningSide }) => winningSide && (event?.eventType !== TEAM || matchUpType === TEAM)
13231
- ).map(
13232
- ({ winningSide, sides }) => winningSide && sides?.[1 - (winningSide - 1)]
13233
- ).map(extractAttributes("participantId")).filter(
13234
- (participantId) => participantId && !assignedParticipantIds.includes(participantId)
14245
+ let validSeedBlocks = seedBlockInfo?.validSeedBlocks;
14246
+ if (!validSeedBlocks && structure) {
14247
+ validSeedBlocks = getValidSeedBlocks({
14248
+ appliedPolicies,
14249
+ drawDefinition,
14250
+ structure
14251
+ })?.validSeedBlocks;
14252
+ }
14253
+ if (appliedPolicies?.seeding?.validSeedPositions?.ignore)
14254
+ return true;
14255
+ if (appliedPolicies?.seeding?.validSeedPositions?.strict) {
14256
+ const targetSeedBlock = validSeedBlocks.find(
14257
+ (seedBlock) => seedBlock.seedNumbers.includes(seedNumber)
13235
14258
  );
13236
- availableParticipantIds?.forEach((participantId) => {
13237
- if (!availableLuckyLoserParticipantIds.includes(participantId))
13238
- availableLuckyLoserParticipantIds.push(participantId);
13239
- });
14259
+ const validSeedPositions2 = targetSeedBlock?.drawPositions || [];
14260
+ return validSeedPositions2.includes(drawPosition);
13240
14261
  }
13241
- const availableLuckyLosers = tournamentParticipants?.filter(
13242
- (participant) => availableLuckyLoserParticipantIds?.includes(participant.participantId)
14262
+ const validSeedPositions = [].concat(
14263
+ ...validSeedBlocks.map((seedBlock) => seedBlock.drawPositions)
13243
14264
  );
13244
- availableLuckyLosers?.forEach((luckyLoser) => {
13245
- const entry = (drawDefinition.entries || []).find(
13246
- (entry2) => entry2.participantId === luckyLoser.participantId
14265
+ return validSeedPositions.includes(drawPosition);
14266
+ }
14267
+ function getNextSeedBlock(params) {
14268
+ const {
14269
+ provisionalPositioning,
14270
+ drawDefinition,
14271
+ seedBlockInfo,
14272
+ structureId,
14273
+ randomize
14274
+ } = params;
14275
+ const { structure } = findStructure({ drawDefinition, structureId });
14276
+ const { seedAssignments } = getStructureSeedAssignments({
14277
+ provisionalPositioning,
14278
+ drawDefinition,
14279
+ structure
14280
+ });
14281
+ const { positionAssignments } = structureAssignedDrawPositions({ structure });
14282
+ const positionsWithParticipants = positionAssignments?.filter(
14283
+ (assignment) => assignment.participantId ?? assignment.bye ?? assignment.qualifier
14284
+ );
14285
+ const assignedDrawPositions = positionsWithParticipants?.map((assignment) => assignment.drawPosition).filter(Boolean);
14286
+ const { appliedPolicies } = getAppliedPolicies({ drawDefinition });
14287
+ const validSeedBlocks = seedBlockInfo?.validSeedBlocks || structure && getValidSeedBlocks({
14288
+ provisionalPositioning,
14289
+ appliedPolicies,
14290
+ drawDefinition,
14291
+ structure
14292
+ })?.validSeedBlocks;
14293
+ const unfilledSeedBlocks = (validSeedBlocks || []).filter((seedBlock) => {
14294
+ const unfilledPositions2 = seedBlock.drawPositions.filter(
14295
+ (drawPosition) => !assignedDrawPositions?.includes(drawPosition)
13247
14296
  );
13248
- luckyLoser.entryPosition = entry?.entryPosition;
14297
+ return unfilledPositions2.length;
13249
14298
  });
13250
- if (availableLuckyLoserParticipantIds?.length) {
13251
- const validLuckyLosersAction = {
13252
- type: LUCKY_PARTICIPANT,
13253
- method: LUCKY_PARTICIPANT_METHOD,
13254
- availableLuckyLosers,
13255
- availableLuckyLoserParticipantIds,
13256
- willDisableLinks: possiblyDisablingAction,
13257
- payload: { drawId, structureId, drawPosition }
13258
- };
13259
- return { validLuckyLosersAction };
14299
+ const nextSeedBlock = unfilledSeedBlocks[0];
14300
+ const assignedSeedParticipantIds = seedAssignments?.map((assignment) => assignment.participantId).filter(Boolean);
14301
+ const assignedPositionParticipantIds = positionAssignments?.map((assignment) => assignment.participantId).filter(Boolean);
14302
+ const placedSeedParticipantIds = assignedSeedParticipantIds?.filter(
14303
+ (participantId) => assignedPositionParticipantIds?.includes(participantId)
14304
+ );
14305
+ const unplacedSeedIds = assignedSeedParticipantIds?.filter(
14306
+ (participantId) => !assignedPositionParticipantIds?.includes(participantId)
14307
+ );
14308
+ const unplacedSeedAssignments = seedAssignments?.filter(
14309
+ (assignment) => unplacedSeedIds?.includes(assignment.participantId)
14310
+ );
14311
+ const seedsWithoutDrawPositions = seedAssignments?.filter(
14312
+ (assignment) => !assignment.participantId
14313
+ );
14314
+ const seedsLeftToAssign = unplacedSeedAssignments?.length && unplacedSeedAssignments.length > 0 ? unplacedSeedAssignments.length : seedsWithoutDrawPositions?.length ?? 0;
14315
+ const unfilled = seedsLeftToAssign && nextSeedBlock?.drawPositions.filter(
14316
+ (drawPosition) => !assignedDrawPositions?.includes(drawPosition)
14317
+ ) || [];
14318
+ const unfilledPositions = randomize ? shuffleArray(unfilled) : unfilled;
14319
+ const selectedParticipantIds = [];
14320
+ const randomlySelectedUnplacedSeedValueIds = unfilledPositions.map(() => {
14321
+ const assignment = randomlySelectLowestSeedValue(
14322
+ unplacedSeedAssignments,
14323
+ selectedParticipantIds
14324
+ );
14325
+ const participantId = assignment?.participantId;
14326
+ if (participantId)
14327
+ selectedParticipantIds.push(participantId);
14328
+ return participantId;
14329
+ }).filter(Boolean);
14330
+ const placedSeedNumbers = seedAssignments?.filter(
14331
+ (assignment) => placedSeedParticipantIds?.includes(assignment.participantId)
14332
+ ).map((assignment) => assignment.seedNumber);
14333
+ const blockSeedNumbers = nextSeedBlock?.seedNumbers || [];
14334
+ const unplacedSeedNumbers = blockSeedNumbers.filter(
14335
+ (seedNumber) => !placedSeedNumbers?.includes(seedNumber)
14336
+ );
14337
+ const unplacedSeedNumberIds = seedAssignments?.filter(
14338
+ (assignment) => unplacedSeedNumbers.includes(assignment.seedNumber)
14339
+ ).map((assignment) => assignment.participantId);
14340
+ const duplicateSeedNumbers = appliedPolicies?.seeding?.duplicateSeedNumbers;
14341
+ const allowsDuplicateSeedNumbers = duplicateSeedNumbers !== void 0 ? duplicateSeedNumbers : true;
14342
+ const unplacedSeedParticipantIds = allowsDuplicateSeedNumbers ? randomlySelectedUnplacedSeedValueIds : unplacedSeedNumberIds;
14343
+ return {
14344
+ nextSeedBlock,
14345
+ unplacedSeedParticipantIds,
14346
+ unplacedSeedNumbers,
14347
+ unfilledPositions,
14348
+ unplacedSeedAssignments
14349
+ };
14350
+ function randomlySelectLowestSeedValue(assignments, selectedParticipantIds2) {
14351
+ const filteredAssignments = assignments.filter(
14352
+ (assignment) => !selectedParticipantIds2.includes(assignment.participantId)
14353
+ );
14354
+ const lowestSeedValue = Math.min(
14355
+ ...filteredAssignments.map(
14356
+ (assignment) => getNumericSeedValue(assignment.seedValue)
14357
+ )
14358
+ );
14359
+ const assignmentsWithLowestSeedValue = filteredAssignments.filter(
14360
+ (assignment) => getNumericSeedValue(assignment.seedValue) === lowestSeedValue
14361
+ );
14362
+ const randomizedAssignments = shuffleArray(assignmentsWithLowestSeedValue);
14363
+ return randomizedAssignments.pop();
13260
14364
  }
13261
- return {};
14365
+ }
14366
+ function getSeedPattern(seedingProfile) {
14367
+ if (typeof seedingProfile === "string")
14368
+ return seedingProfile;
14369
+ if (typeof seedingProfile === "object")
14370
+ return seedingProfile.positioning;
13262
14371
  }
13263
14372
 
13264
14373
  function getValidAssignmentActions({
@@ -13842,14 +14951,14 @@ function positionActions$1(params) {
13842
14951
  (assignment) => assignment.participantId === participantId
13843
14952
  ) || {};
13844
14953
  validActions.push({
13845
- type: REMOVE_SEED,
13846
14954
  method: REMOVE_SEED_METHOD,
14955
+ type: REMOVE_SEED,
13847
14956
  participant,
13848
14957
  seedNumber,
13849
14958
  payload: {
13850
- drawId,
14959
+ participantId,
13851
14960
  structureId,
13852
- participantId
14961
+ drawId
13853
14962
  }
13854
14963
  });
13855
14964
  }
@@ -13860,11 +14969,11 @@ function positionActions$1(params) {
13860
14969
  method: ADD_PENALTY_METHOD,
13861
14970
  participant,
13862
14971
  payload: {
13863
- drawId,
13864
14972
  penaltyCode: void 0,
13865
14973
  penaltyType: void 0,
13866
14974
  participantIds: [],
13867
- notes: void 0
14975
+ notes: void 0,
14976
+ drawId
13868
14977
  }
13869
14978
  };
13870
14979
  validActions.push(addPenaltyAction);
@@ -13963,9 +15072,9 @@ function positionActions(params) {
13963
15072
  const { tournamentRecord } = params;
13964
15073
  if (!tournamentRecord)
13965
15074
  return { error: MISSING_TOURNAMENT_RECORD };
13966
- const { tournamentParticipants } = getTournamentParticipants({
13967
- tournamentRecord,
13968
- inContext: true
15075
+ const { participants: tournamentParticipants } = getParticipants({
15076
+ withIndividualParticipants: true,
15077
+ tournamentRecord
13969
15078
  });
13970
15079
  return positionActions$1({
13971
15080
  tournamentParticipants,
@@ -13973,6 +15082,8 @@ function positionActions(params) {
13973
15082
  });
13974
15083
  }
13975
15084
 
15085
+ const hasParticipantId = (o) => o?.participantId;
15086
+
13976
15087
  function getStructureGroups({ drawDefinition }) {
13977
15088
  const links = drawDefinition.links || [];
13978
15089
  const sourceStructureIds = {};
@@ -14217,7 +15328,7 @@ function getEventData(params) {
14217
15328
  event
14218
15329
  });
14219
15330
  const publishStatus = timeItem?.itemValue?.[status];
14220
- const { tournamentParticipants } = getTournamentParticipants({
15331
+ const { participants: tournamentParticipants } = getParticipants({
14221
15332
  withGroupings: true,
14222
15333
  withEvents: false,
14223
15334
  withDraws: false,