using System.Collections.Generic;
namespace OpenNest.Benchmark
{
///
/// Outcome of running one engine against one job. A job may span several
/// plates (PlatesUsed, SizeBreakdown), since the engine may need more than
/// one sheet - possibly of different sizes - to place everything asked of
/// it. An invalid or crashed run places nothing as far as scoring is
/// concerned: it earns no area and pays the unplaced penalty on every
/// requested part.
///
public class JobResult
{
public string EngineName { get; init; }
public string JobName { get; init; }
public bool Valid { get; init; }
public List Violations { get; init; } = new();
public string Error { get; init; }
public int PartsPlaced { get; init; }
public int PartsRequested { get; init; }
public double PlacedArea { get; init; }
public double PlateArea { get; init; }
/// Sheet area consumed after crediting salvageable offcuts
/// (StockLadderNestingEngine.EstimateNetArea summed over every plate).
/// Equals PlateArea when salvage credit is disabled.
public double NetSheetArea { get; init; }
/// Sheet area charged for each requested part that was not
/// placed: the largest candidate sheet's area, so leaving a part out
/// always costs at least as much as the extra sheet it would need.
public double UnplacedPartPenalty { get; init; }
public int PlatesUsed { get; init; }
public Dictionary SizeBreakdown { get; init; } = new();
public long ElapsedMs { get; init; }
public bool Crashed => Error != null;
public bool FullyPlaced => Valid && PartsRequested > 0 && PartsPlaced >= PartsRequested;
/// Aggregate utilization across every plate the engine used:
/// total placed drawing area over total plate area, matching
/// Plate.Utilization()'s per-plate definition summed across the job.
public double Utilization => Valid && PlateArea > 0 ? PlacedArea / PlateArea : 0;
/// Placed area over salvage-credited sheet area.
public double NetUtilization =>
Valid && NetSheetArea > 0 ? PlacedArea / NetSheetArea : 0;
public int PartsUnplaced =>
Valid ? System.Math.Max(0, PartsRequested - PartsPlaced) : PartsRequested;
///
/// The ranking score, in sheet area (lower is better): net sheet area
/// consumed plus the unplaced penalty. An engine cannot improve it by
/// dropping awkward parts, and it sums honestly across jobs of
/// different sizes. Invalid runs consume no sheet but pay the penalty
/// on every requested part.
///
public double Cost => (Valid ? NetSheetArea : 0) + PartsUnplaced * UnplacedPartPenalty;
}
}