tods-competition-factory 1.7.19 → 1.8.0

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