// TABLES 段:图纸用到的那几张「字典」——图层、线型、文字样式、标注样式、块记录。
//
// 文件里的长相是这样:
//
//     0   TABLE
//     2   LAYER          ← 表的种类
//     70  3              ← 这条表里有多少项(**不可信**,见下)
//     0   LAYER          ← 一项
//     2   轮廓            ← 图层名
//     70  0              ← 标志位(冻结/锁定…)
//     62  1              ← 颜色
//     0   LAYER
//     ...
//     0   ENDTAB
//
// 两层 `0` 记录:`TABLE` 包着一堆同类型的记录,`ENDTAB` 收尾。
//
// 这里也是「**组码 70 含义随子类变**」最典型的例子:
//
//     100 AcDbSymbolTable       ← 在这条子类里,70 是「表里有多少项」
//     70  3
//     100 AcDbLayerTableRecord  ← 在这条子类里,70 是「图层标志位」
//     70  4
//
// 同一个组码、同一份文件、意思完全不同。所以取标志位必须用
// `get_in(record, "AcDbLayerTableRecord", 70)`,不能用笼统的 `get`。

// ── 图层 ────────────────────────────────────────────────────────────────

///|
/// 一个图层。
pub(all) struct Layer {
  name : String
  /// ACI 索引色(1-255)。**负值表示图层被关闭**,绝对值才是颜色
  color : Int
  /// 线型名
  linetype : String
  /// 冻结标志;本工具默认检查跳过,不推断下游加工行为。
  frozen : Bool
  /// 锁定标志;本工具不将锁定状态作为检查筛选条件。
  locked : Bool
  /// 线宽,单位是百分之一毫米(-3 表示「用默认值」)
  lineweight : Int
}

///|
/// 图层是不是关着的。
///
/// DXF 用**颜色的符号**表示开关,不是单独一个标志位——
/// 这一点不看规范很难猜到。
pub fn Layer::is_off(self : Layer) -> Bool {
  self.color < 0
}

///|
/// 图层实际的颜色索引(取绝对值)。
pub fn Layer::color_index(self : Layer) -> Int {
  if self.color < 0 {
    -self.color
  } else {
    self.color
  }
}

///|
/// 是否按本工具默认规则参与部分几何检查,不表示 CAM 或机床行为。
pub fn Layer::is_enabled_for_checks(self : Layer) -> Bool {
  !self.is_off() && !self.frozen
}

///|
/// 兼容旧接口;仅表示本工具检查筛选规则,不表示能否加工。
/// 文档弃用:新代码使用 `Layer::is_enabled_for_checks()`;本版保留同义行为。
/// 未添加编译器 deprecated 属性,以免兼容调用在 --deny-warn 下成为错误。
pub fn Layer::is_machinable(self : Layer) -> Bool {
  self.is_enabled_for_checks()
}

// ── 表 ──────────────────────────────────────────────────────────────────

///|
/// TABLES 段。
pub(all) struct Tables {
  layers : Array[Layer]
  /// 线型名(`CONTINUOUS` / `DASHED` / …)
  linetypes : Array[String]
  /// 文字样式名
  text_styles : Array[String]
  /// 块记录名。和 BLOCKS 段里的块定义一一对应
  block_records : Array[String]
}

///|
/// 解析 TABLES 段。
///
/// 只认这四张表——别的一律跳过,但**跳过是按结构跳的**(认 `TABLE`/`ENDTAB`
/// 的层次),不是按关键字。否则遇到没见过的表名会把它的内容当成外层记录。
pub fn parse_tables(section : Section) -> Tables {
  let layers : Array[Layer] = []
  let linetypes : Array[String] = []
  let text_styles : Array[String] = []
  let block_records : Array[String] = []

  // 当前在哪张表里
  let mut table_kind : String? = None

  for record in section.records {
    if record.kind == "TABLE" {
      table_kind = Some(record.get_string(2))
    } else if record.kind == "ENDTAB" {
      table_kind = None
    } else {
      match table_kind {
        Some(kind) =>
          if kind == "LAYER" && record.kind == "LAYER" {
            layers.push(parse_layer(record))
          } else if kind == "LTYPE" && record.kind == "LTYPE" {
            linetypes.push(record.get_string(2))
          } else if kind == "STYLE" && record.kind == "STYLE" {
            text_styles.push(record.get_string(2))
          } else if kind == "BLOCK_RECORD" && record.kind == "BLOCK_RECORD" {
            block_records.push(record.get_string(2))
          }
        None => ()
      }
    }
  }
  { layers, linetypes, text_styles, block_records, }
}

///|
/// 解析一个图层记录。
fn parse_layer(record : Record) -> Layer {
  let sub = "AcDbLayerTableRecord"
  // 标志位必须**指定子类**去取——直接 get(70) 拿到的可能是
  // AcDbSymbolTable 里的「表里有多少项」
  let flags = match record.get_in(sub, 70) {
    Some(t) => t.value.as_int()
    None => 0
  }
  Layer::{
    name: record.get_string(2),
    color: match record.get_in(sub, 62) {
      Some(t) => t.value.as_int()
      None => 7 // 没写颜色时 DXF 的默认色是 7(白/黑)
    },
    linetype: match record.get_in(sub, 6) {
      Some(t) => t.value.as_string()
      None => "CONTINUOUS"
    },
    // 标志位的位含义:1 = 冻结、4 = 锁定
    frozen: (flags & 1) != 0,
    locked: (flags & 4) != 0,
    lineweight: record.get_int(370, -3),
  }
}

///|
/// 按名字找图层。
pub fn Tables::layer(self : Tables, name : String) -> Layer? {
  for l in self.layers {
    if l.name == name {
      return Some(l)
    }
  }
  None
}