Files
CMS/src/CMSMicroservice.Infrastructure/Services/NetworkPlacementService.cs

117 lines
4.1 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Enums;
using System.Collections.Generic;
namespace CMSMicroservice.Infrastructure.Services;
/// <summary>
/// پیاده‌سازی سرویس محاسبه موقعیت در Binary Tree
/// </summary>
public class NetworkPlacementService : INetworkPlacementService
{
private readonly IApplicationDbContext _context;
private readonly ILogger<NetworkPlacementService> _logger;
public NetworkPlacementService(
IApplicationDbContext context,
ILogger<NetworkPlacementService> logger)
{
_context = context;
_logger = logger;
}
public async Task<NetworkLeg?> CalculateLegPositionAsync(long parentId, CancellationToken cancellationToken = default)
{
// بررسی وجود Parent
var parentExists = await _context.Users.AnyAsync(u => u.Id == parentId, cancellationToken);
if (!parentExists)
{
_logger.LogWarning("Parent {ParentId} does not exist", parentId);
return null;
}
// شمارش فرزندان فعلی
var children = await _context.Users
.Where(u => u.NetworkParentId == parentId)
.Select(u => new { u.LegPosition })
.ToListAsync(cancellationToken);
if (children.Count >= 2)
{
_logger.LogWarning("Parent {ParentId} already has 2 children. Binary Tree is full!", parentId);
return null; // Binary Tree پر است
}
// بررسی کدام Leg خالی است
var hasLeft = children.Any(c => c.LegPosition == NetworkLeg.Left);
var hasRight = children.Any(c => c.LegPosition == NetworkLeg.Right);
if (!hasLeft)
{
_logger.LogDebug("Parent {ParentId}: Left leg is available", parentId);
return NetworkLeg.Left;
}
if (!hasRight)
{
_logger.LogDebug("Parent {ParentId}: Right leg is available", parentId);
return NetworkLeg.Right;
}
// نباید به اینجا برسیم (چون Count < 2 بود)
_logger.LogError("Unexpected state: Parent {ParentId} has {Count} children but no available leg",
parentId, children.Count);
return null;
}
public async Task<bool> CanAcceptChildAsync(long parentId, CancellationToken cancellationToken = default)
{
var childCount = await _context.Users
.CountAsync(u => u.NetworkParentId == parentId, cancellationToken);
return childCount < 2;
}
public async Task<long?> FindAvailableParentAsync(long rootParentId, CancellationToken cancellationToken = default)
{
// BFS (Breadth-First Search) برای پیدا کردن اولین Parent با جای خالی
var queue = new Queue<long>();
queue.Enqueue(rootParentId);
var visited = new HashSet<long>();
while (queue.Count > 0)
{
var currentParentId = queue.Dequeue();
if (visited.Contains(currentParentId))
continue;
visited.Add(currentParentId);
// بررسی کنید که آیا این Parent می‌تواند فرزند بپذیرد
var canAccept = await CanAcceptChildAsync(currentParentId, cancellationToken);
if (canAccept)
{
_logger.LogInformation("Found available parent: {ParentId}", currentParentId);
return currentParentId;
}
// اضافه کردن فرزندان به صف برای جستجو
var children = await _context.Users
.Where(u => u.NetworkParentId == currentParentId)
.Select(u => u.Id)
.ToListAsync(cancellationToken);
foreach (var childId in children)
{
queue.Enqueue(childId);
}
}
_logger.LogWarning("No available parent found in network starting from {RootParentId}", rootParentId);
return null; // هیچ Parent خالی پیدا نشد
}
}