// 批量跑语料,把结果打出来。
//
//     moon run conformance                  # 每个文件的 tag 数、警告数、编码
//     moon run conformance --info           # 结构报告:版本、段、图层、块
//     moon run conformance -- --audit       # 逐文件分层观察,JSON Lines;不宣称几何已验证
//     moon run conformance --svg 文件.dxf    # 画成 SVG 打到 stdout
//     moon run conformance 某文件.dxf        # 只跑一个(默认是 tag 报告)
//
// 用途有两个:改了解析器之后**一眼看出有没有文件被跑挂**,
// 以及把每个文件的实际数字记下来当锚点。

///|
fn main {
  let args = @env.args()
  let mut info_mode = false
  let mut svg_mode = false
  let mut audit_mode = false
  let mut targets : Array[String] = []
  for i = 1; i < args.length(); i = i + 1 {
    if args[i] == "--info" {
      info_mode = true
    } else if args[i] == "--svg" {
      svg_mode = true
    } else if args[i] == "--audit" {
      audit_mode = true
    } else {
      targets.push(args[i])
    }
  }
  if svg_mode {
    report_svg(targets)
    return
  }
  if targets.length() == 0 {
    targets = corpus_files() catch {
      err => {
        println("读不了语料目录 \{CORPUS_DIR}:\{err}")
        return
      }
    }
  }
  if audit_mode {
    report_corpus_audit(targets)
  } else if info_mode {
    report_info(targets)
  } else {
    report_tags(targets)
  }
}

///|
/// SVG 预览:把文件展开后的几何画成 SVG 打到 stdout——
///
///     moon run conformance --svg 某文件.dxf > 预览.svg
fn report_svg(targets : Array[String]) -> Unit {
  if targets.length() == 0 {
    println(
      "--svg 后面要给一个文件:moon run conformance --svg 某文件.dxf",
    )
    return
  }
  // 预览的离散容差取 0.05——和语料锚点一个口径,肉眼够用
  for path in targets {
    let scan = scan_corpus_file(path) catch {
      err => {
        println("读不了 \{path}:\{err}")
        continue
      }
    }
    let drawing = @dxfkit.build_drawing(scan)
    println(drawing.to_svg(0.05))
  }
}

///|
/// tag 报告:每个文件扫出多少 tag、多少警告、判定成什么编码。
fn report_tags(targets : Array[String]) -> Unit {
  let mut total_tags = 0
  let mut total_warnings = 0
  let mut failed = 0

  println(
    "文件                                      tag 数   警告  编码",
  )
  println(
    "──────────────────────────────────────────────────────────────────",
  )
  for path in targets {
    let scan = scan_corpus_file(path) catch {
      err => {
        println("\{short_name(path)}:读不了(\{err})")
        failed = failed + 1
        continue
      }
    }
    println(
      "\{pad(short_name(path), 40)} \{pad_int(scan.tags.length(), 6)} " +
      "\{pad_int(scan.warnings.length(), 6)}  \{scan.encoding.to_display()}",
    )
    total_tags = total_tags + scan.tags.length()
    total_warnings = total_warnings + scan.warnings.length()
  }
  println(
    "──────────────────────────────────────────────────────────────────",
  )
  println(
    "\{targets.length()} 个文件,共 \{total_tags} 个 tag," +
    "\{total_warnings} 条警告,\{failed} 个读不了",
  )
}

///|
/// 结构报告:版本、每个段有多少条记录、图层和块。
fn report_info(targets : Array[String]) -> Unit {
  let mut failed = 0
  for path in targets {
    let scan = scan_corpus_file(path) catch {
      err => {
        println("\{short_name(path)}:读不了(\{err})")
        failed = failed + 1
        continue
      }
    }
    let drawing = @dxfkit.build_drawing(scan)
    println("═══ \{short_name(path)} ═══")
    println(
      "  版本      \{if drawing.version == "" { "(没有 HEADER 段)" } else { drawing.version }}",
    )

    // 段的记录数
    let sb = StringBuilder()
    let mut first = true
    for s in drawing.sections {
      if !first {
        sb.write_string("  ")
      }
      first = false
      sb.write_string("\{s.name}(\{s.records.length()})")
    }
    println("  段        \{sb}")

    // 图层
    match drawing.section("TABLES") {
      Some(t) => {
        let tables = @dxfkit.parse_tables(t)
        println("  图层      \{tables.layers.length()} 个")
        for l in tables.layers {
          let marks = StringBuilder()
          if l.is_off() {
            marks.write_string(" 关闭")
          }
          if l.frozen {
            marks.write_string(" 冻结")
          }
          if l.locked {
            marks.write_string(" 锁定")
          }
          println(
            "    \{pad(l.name, 24)} 颜色 \{pad_int(l.color_index(), 3)}\{marks}",
          )
        }
        println("  线型      \{tables.linetypes.length()} 个")
        println("  块记录    \{tables.block_records.length()} 个")
      }
      None => println("  没有 TABLES 段")
    }

    // HEADER 的常用变量
    match drawing.section("HEADER") {
      Some(h) => {
        let header = @dxfkit.parse_header(h)
        let units = header.insunits()
        println("  单位      \{units}(\{@dxfkit.unit_name(units)})")
        match (header.extmin(), header.extmax()) {
          (Some(lo), Some(hi)) =>
            println("  范围      (\{lo.x}, \{lo.y}) 到 (\{hi.x}, \{hi.y})")
          (Some(lo), None) =>
            println("  范围      左下 (\{lo.x}, \{lo.y}),没有 $EXTMAX")
          (None, Some(hi)) =>
            println("  范围      右上 (\{hi.x}, \{hi.y}),没有 $EXTMIN")
          (None, None) => ()
        }
      }
      None => ()
    }
    if drawing.warnings.length() > 0 {
      println("  警告      \{drawing.warnings.length()} 条")
      for w in drawing.warnings {
        println("    \{w}")
      }
    }
    println("")
  }
  if failed > 0 {
    println("\{failed} 个文件读不了")
  }
}

///|
/// 只留文件名,报告里短一点。
fn short_name(path : String) -> String {
  let mut start = 0
  for i = 0; i < path.length(); i = i + 1 {
    let c = path.code_unit_at(i).to_int()
    if c == 0x2F || c == 0x5C {
      start = i + 1
    }
  }
  path[start:].to_owned()
}

///|
/// 左侧对齐补空格。
fn pad(s : String, width : Int) -> String {
  let sb = StringBuilder()
  sb.write_string(s)
  let mut i = s.length()
  while i < width {
    sb.write_string(" ")
    i = i + 1
  }
  sb.to_string()
}

///|
/// 右侧对齐补空格。
fn pad_int(n : Int, width : Int) -> String {
  let s = n.to_string()
  let sb = StringBuilder()
  let mut i = s.length()
  while i < width {
    sb.write_string(" ")
    i = i + 1
  }
  sb.write_string(s)
  sb.to_string()
}