// Licensed to the LF AI & Data foundation under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// 行的读接口。上游 `Column` 接口有 `Get / GetAsInt64 / GetAsString /
// GetAsDouble / GetAsBool / IsNull / Len`;这里保留 `Len`、`IsNull` 和
// 一个按列类型返回的 `Get`(`Cell`),外加 `GetAs*` 会拒绝跨类型读取
// 的那几个——不做隐式转换,读错类型就是 bug,早点报出来。

///|
/// 一行的值。与 `ColumnValue` 一一对应,只是每项至多一个元素。
///
/// `Null` 单独一个成员,而不是让 `Get` 返回 `Cell?`:一整列全空时
/// 仍要能区分「第 3 行是 null」和「列就这么长」,`Cell` 自己承载这个区别。
pub(all) enum Cell {
  Bool(Bool)
  Int8(Int)
  Int16(Int)
  Int32(Int)
  Int64(Int64)
  Float(Float)
  Double(Double)
  String(String)
  VarChar(String)
  Text(String)
  Timestamptz(Int64)
  Json(Bytes)
  Geometry(String)
  Array(ArrayValue)
  FloatVector(Array[Float])
  Float16Vector(Array[Float])
  BFloat16Vector(Array[Float])
  BinaryVector(Bytes)
  Int8Vector(Bytes)
  SparseFloatVector(@entity.SparseFloatVector)
  Null
} derive(Eq, Debug)

///|
/// 逻辑行数。可空列以 `valid` 的长度为准——数据行可能比它短,那是紧凑
/// 布局;非空列就是数据的长度。
pub fn Column::len(self : Column) -> Int {
  if self.nullable {
    self.valid.length()
  } else {
    match self.column {
      Bool(v) => v.length()
      Int8(v) | Int16(v) | Int32(v) => v.length()
      Int64(v) | Timestamptz(v) => v.length()
      Float(v) => v.length()
      Double(v) => v.length()
      String(v) | VarChar(v) | Text(v) | Geometry(v) => v.length()
      Json(v) => v.length()
      Array(v) => v.length()
      FloatVector(_, v) | Float16Vector(_, v) | BFloat16Vector(_, v) =>
        v.length()
      BinaryVector(_, v) | Int8Vector(_, v) => v.length()
      SparseFloatVector(v) => v.length()
    }
  }
}

///|
/// 第 `idx` 行是否为 null。越界报错;非空列恒为 `false`。
pub fn Column::is_null(self : Column, idx : Int) -> Bool raise ColumnError {
  if idx < 0 || idx >= self.len() {
    raise IndexOutOfRange("row index \{idx} out of range [0, \{self.len()})")
  }
  if self.nullable {
    !self.valid[idx]
  } else {
    false
  }
}

///|
/// 有效行数:`valid` 里 `true` 的个数,非空列等于 `len()`。
/// 上游 `ValidCount`。
pub fn Column::valid_count(self : Column) -> Int {
  if !self.nullable {
    return self.len()
  }
  let mut count = 0
  for v in self.valid {
    if v {
      count = count + 1
    }
  }
  count
}

///|
/// 第 `idx` 行的值。null 行返回 `Cell::Null`。
///
/// 可空列的数据按上游约定分两种布局:`valid` 长度等于数据长度时(行满)
/// 数据行与逻辑行一一对应;否则数据是紧凑的,null 行不占位,需要把逻辑
/// 下标映射到物理下标。`value_index` 负责这件事,下面所有取值都走它。
pub fn Column::get(self : Column, idx : Int) -> Cell raise ColumnError {
  if idx < 0 || idx >= self.len() {
    raise IndexOutOfRange("row index \{idx} out of range [0, \{self.len()})")
  }
  if self.nullable && !self.valid[idx] {
    return Null
  }
  let j = self.value_index(idx)
  match self.column {
    Bool(v) => Bool(v[j])
    Int8(v) => Int8(v[j])
    Int16(v) => Int16(v[j])
    Int32(v) => Int32(v[j])
    Int64(v) => Int64(v[j])
    Float(v) => Float(v[j])
    Double(v) => Double(v[j])
    String(v) => String(v[j])
    VarChar(v) => VarChar(v[j])
    Text(v) => Text(v[j])
    Timestamptz(v) => Timestamptz(v[j])
    Json(v) => Json(v[j])
    Geometry(v) => Geometry(v[j])
    Array(v) => Array(v[j])
    FloatVector(_, v) => FloatVector(v[j])
    Float16Vector(_, v) => Float16Vector(v[j])
    BFloat16Vector(_, v) => BFloat16Vector(v[j])
    BinaryVector(_, v) => BinaryVector(v[j])
    Int8Vector(_, v) => Int8Vector(v[j])
    SparseFloatVector(v) => SparseFloatVector(v[j])
  }
}

///|
/// 第 `idx` 行在数据数组里的物理下标。
///
/// 只有「可空且紧凑」才需要映射:数据长度小于逻辑行数。行满布局里
/// 物理下标就是逻辑下标,上游 `genericColumnBase.valueIndex` 同理。
fn Column::value_index(self : Column, idx : Int) -> Int {
  if !self.nullable || self.data_len() == self.valid.length() {
    return idx
  }
  let mut seen = 0
  for i = 0; i < idx; i = i + 1 {
    if self.valid[i] {
      seen = seen + 1
    }
  }
  seen
}

///|
/// 数据数组的长度。用于判断紧凑布局,不参与任何取值。
fn Column::data_len(self : Column) -> Int {
  match self.column {
    Bool(v) => v.length()
    Int8(v) | Int16(v) | Int32(v) => v.length()
    Int64(v) | Timestamptz(v) => v.length()
    Float(v) => v.length()
    Double(v) => v.length()
    String(v) | VarChar(v) | Text(v) | Geometry(v) => v.length()
    Json(v) => v.length()
    Array(v) => v.length()
    FloatVector(_, v) | Float16Vector(_, v) | BFloat16Vector(_, v) => v.length()
    BinaryVector(_, v) | Int8Vector(_, v) => v.length()
    SparseFloatVector(v) => v.length()
  }
}

///|
/// 圈出 `[begin, end)` 这几行,得到一列等价的窄列。`end` 为负表示到末尾,
/// 与 `from_field_data` 的区间参数同一套约定。越界即夹取,不报错 ——
/// 想取 5 行而列里只有 2 行,是调用方正常会撞上的情形,不是 bug。
///
/// 与 `from_field_data` 的 `begin` / `end` 是同一件事,区别是那个作用于
/// 线上 payload(还没成列),这个作用于已经解好的列。
pub fn Column::slice(self : Column, begin : Int, end : Int) -> Column {
  let n = self.len()
  let b = clamp_begin(begin, n)
  let e = normalize_end(end, n)
  if b >= e {
    return empty_like(self)
  }
  let valid = if self.nullable { self.valid[b:e].to_owned() } else { [] }
  build(slice_value(self, b, e), valid)
}

///|
/// 数据数组的那一段。可空紧凑布局下物理下标与逻辑下标不是一回事,
/// 得先把 `[b, e)` 映射到物理区间再切。
fn slice_value(column : Column, begin : Int, end : Int) -> ColumnValue {
  let (lo, hi) = if column.nullable &&
    column.data_len() != column.valid.length() {
    (rank_before(column, begin), rank_before(column, end))
  } else {
    (begin, end)
  }
  slice_value_range(column.column, lo, hi)
}

///|
/// `[0, idx)` 里的有效行数,也就是物理下标的前缀和。
fn rank_before(column : Column, idx : Int) -> Int {
  let mut count = 0
  for i = 0; i < idx && i < column.valid.length(); i = i + 1 {
    if column.valid[i] {
      count = count + 1
    }
  }
  count
}

///|
fn slice_value_range(
  value : ColumnValue,
  begin : Int,
  end : Int,
) -> ColumnValue {
  match value {
    Bool(v) => Bool(v[begin:end].to_owned())
    Int8(v) => Int8(v[begin:end].to_owned())
    Int16(v) => Int16(v[begin:end].to_owned())
    Int32(v) => Int32(v[begin:end].to_owned())
    Int64(v) => Int64(v[begin:end].to_owned())
    Float(v) => Float(v[begin:end].to_owned())
    Double(v) => Double(v[begin:end].to_owned())
    String(v) => String(v[begin:end].to_owned())
    VarChar(v) => VarChar(v[begin:end].to_owned())
    Text(v) => Text(v[begin:end].to_owned())
    Timestamptz(v) => Timestamptz(v[begin:end].to_owned())
    Json(v) => Json(v[begin:end].to_owned())
    Geometry(v) => Geometry(v[begin:end].to_owned())
    Array(v) => Array(v[begin:end].to_owned())
    FloatVector(dim, v) => FloatVector(dim, v[begin:end].to_owned())
    Float16Vector(dim, v) => Float16Vector(dim, v[begin:end].to_owned())
    BFloat16Vector(dim, v) => BFloat16Vector(dim, v[begin:end].to_owned())
    BinaryVector(dim, v) => BinaryVector(dim, v[begin:end].to_owned())
    Int8Vector(dim, v) => Int8Vector(dim, v[begin:end].to_owned())
    SparseFloatVector(v) => SparseFloatVector(v[begin:end].to_owned())
  }
}

///|
/// 同类型同维度的空列,用于「这一页没有行」。
fn empty_like(column : Column) -> Column {
  build(slice_value_range(column.column, 0, 0), [])
}