using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Comparison;

/// <summary>同一粗路径的离线平滑比较请求。</summary>
public sealed class PathSmoothingComparisonRequest
{
    private static readonly SmoothingMethod[] DefaultMethods =
    {
        SmoothingMethod.CubicBSpline,
        SmoothingMethod.LocalCubicBezier,
        SmoothingMethod.PiecewiseQuintic,
    };

    /// <summary>创建比较请求，并固定原始输入与方法顺序。</summary>
    public PathSmoothingComparisonRequest(
        PathSmoothingRequest smoothingRequest,
        IReadOnlyList<SmoothingMethod> methods = null)
    {
        SmoothingRequest = CopyRequest(smoothingRequest);
        Methods = CopyMethods(methods ?? DefaultMethods);
    }

    /// <summary>所有方法共享的不可变粗路径、地图、车辆和配置快照。</summary>
    public PathSmoothingRequest SmoothingRequest { get; }

    /// <summary>按调用方指定稳定顺序运行的方法集合。</summary>
    public IReadOnlyList<SmoothingMethod> Methods { get; }

    private static PathSmoothingRequest CopyRequest(PathSmoothingRequest source)
    {
        if (source == null) return null;
        return new PathSmoothingRequest(
            source.CoarsePath,
            source.Segments,
            source.Map,
            source.Vehicle,
            source.Configuration);
    }

    private static IReadOnlyList<SmoothingMethod> CopyMethods(IReadOnlyList<SmoothingMethod> source)
    {
        var copy = new List<SmoothingMethod>(source == null ? 0 : source.Count);
        if (source != null)
        {
            for (int index = 0; index < source.Count; index++)
            {
                SmoothingMethod method = source[index];
                if (!Enum.IsDefined(typeof(SmoothingMethod), method))
                    throw new ArgumentOutOfRangeException(nameof(source), "比较方法无效。");
                if (copy.Contains(method))
                    throw new ArgumentException("比较方法不能重复。", nameof(source));
                copy.Add(method);
            }
        }
        return new ReadOnlyCollection<SmoothingMethod>(copy);
    }
}
