///|
/// A portable package descriptor for a trace analysis artifact.
pub struct TracePackageDescriptor {
  name : String
  version : String
  schema_version : String
  capabilities : Array[String]
  dependencies : Array[String]
  reproducible : Bool
} derive(Debug)

///|
/// A package descriptor plus its trace manifest.
pub struct TracePackage {
  descriptor : TracePackageDescriptor
  manifest : TraceManifest
  readme : String
} derive(Debug)

///|
/// Create a descriptor for the built-in analysis package.
pub fn default_trace_package_descriptor() -> TracePackageDescriptor {
  {
    name: "moonbit-vcd-analysis",
    version: "1.0",
    schema_version: "1",
    capabilities: [
      "parse", "validate", "index", "protocol", "coverage", "assertion", "export",
    ],
    dependencies: [],
    reproducible: true,
  }
}

///|
/// Package a trace with its reproducibility manifest.
pub fn package_trace(trace : Trace, name : String) -> TracePackage {
  let descriptor = default_trace_package_descriptor()
  let manifest = trace_manifest(name, trace, descriptor.capabilities.copy())
  { descriptor, manifest, readme: "Portable waveform analysis package" }
}

///|
/// Check package compatibility with the current trace shape.
pub fn TracePackage::compatible(self : TracePackage, trace : Trace) -> Bool {
  self.manifest.signal_count == trace.signals.length() &&
  self.manifest.change_count == trace.changes.length()
}

///|
/// Render package metadata as JSON.
pub fn TracePackage::to_json(self : TracePackage) -> String {
  "{\"name\":\"" +
  self.descriptor.name +
  "\",\"version\":\"" +
  self.descriptor.version +
  "\",\"schema_version\":\"" +
  self.descriptor.schema_version +
  "\",\"reproducible\":" +
  self.descriptor.reproducible.to_string() +
  ",\"capabilities\":[" +
  self.descriptor.capabilities.map(fn(item) { "\"" + item + "\"" }).join(",") +
  "],\"manifest\":" +
  self.manifest.to_json() +
  "}"
}

///|
/// Render package metadata for terminal output.
pub fn TracePackage::to_text(self : TracePackage) -> String {
  self.descriptor.name +
  " " +
  self.descriptor.version +
  " capabilities=" +
  self.descriptor.capabilities.length().to_string() +
  " reproducible=" +
  self.descriptor.reproducible.to_string()
}

///|
/// Return whether a capability is advertised.
pub fn TracePackage::supports(self : TracePackage, capability : String) -> Bool {
  self.descriptor.capabilities.contains(capability)
}