using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Enums; using System.Collections.Generic; namespace CMSMicroservice.Infrastructure.Services; /// /// پیاده‌سازی سرویس محاسبه موقعیت در Binary Tree /// public class NetworkPlacementService : INetworkPlacementService { private readonly IApplicationDbContext _context; private readonly ILogger _logger; public NetworkPlacementService( IApplicationDbContext context, ILogger logger) { _context = context; _logger = logger; } public async Task 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 CanAcceptChildAsync(long parentId, CancellationToken cancellationToken = default) { var childCount = await _context.Users .CountAsync(u => u.NetworkParentId == parentId, cancellationToken); return childCount < 2; } public async Task FindAvailableParentAsync(long rootParentId, CancellationToken cancellationToken = default) { // BFS (Breadth-First Search) برای پیدا کردن اولین Parent با جای خالی var queue = new Queue(); queue.Enqueue(rootParentId); var visited = new HashSet(); 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 خالی پیدا نشد } }