// MoonDatalog —— 元组(Tuple)与关系(Relation)
//
// 关系是一组同构元组的集合,配合按首参数建立的哈希索引,
// 用于支撑 bottom-up / semi-naive 求值中的连接(join)操作。

///|
/// 一个关系元组:有序的值数组。
///
/// 自定义 `Eq` / `Hash` / `Compare`,使元组可作为哈希集合的元素,
/// 并按字典序可比,从而支持去重与排序输出。
pub struct Tuple {
  elems : Array[Value]
}

///|
pub fn make_tuple(values : Array[Value]) -> Tuple {
  { elems: values }
}

///|
pub fn Tuple::get(self : Tuple, i : Int) -> Value {
  self.elems[i]
}

///|
pub fn Tuple::length(self : Tuple) -> Int {
  self.elems.length()
}

///|
/// 以 `(a, b, c)` 形式输出。
pub fn Tuple::to_string(self : Tuple) -> String {
  let b = StringBuilder::new()
  b.write_char('(')
  let mut first = true
  for e in self.elems {
    if first {
      first = false
    } else {
      b.write_string(", ")
    }
    b.write_string(e.to_string())
  }
  b.write_char(')')
  b.to_string()
}

///|
pub impl Eq for Tuple with fn equal(self : Tuple, that : Tuple) -> Bool {
  if self.elems.length() != that.elems.length() {
    return false
  }
  let mut i = 0
  while i < self.elems.length() {
    if self.elems[i] != that.elems[i] {
      return false
    }
    i = i + 1
  }
  true
}

///|
/// 字典序比较;长度不同时较短者在前(与常见元组序一致)。
pub impl Compare for Tuple with fn compare(self : Tuple, that : Tuple) -> Int {
  let n = self.elems.length().min(that.elems.length())
  let mut i = 0
  while i < n {
    let c = compare_values(self.elems[i], that.elems[i])
    if c != 0 {
      return c
    }
    i = i + 1
  }
  self.elems.length() - that.elems.length()
}

///|
pub impl Hash for Tuple with fn hash_combine(self : Tuple, hasher : Hasher) -> Unit {
  hasher.combine_int(self.elems.length())
  for e in self.elems {
    hasher.combine(e)
  }
}

///|
/// 一个关系(谓词实例):同元数元组的集合,并维护按首参数的值索引。
pub struct Relation {
  arity : Int
  tuples : @hashset.HashSet[Tuple]
  idx0 : @hashmap.HashMap[Value, @hashset.HashSet[Tuple]]
}

///|
pub fn new_relation(arity : Int) -> Relation {
  { arity, tuples: @hashset.HashSet([]), idx0: @hashmap.HashMap([]) }
}

///|
pub fn Relation::arity(self : Relation) -> Int {
  self.arity
}

///|
pub fn Relation::length(self : Relation) -> Int {
  self.tuples.length()
}

///|
/// 插入一个元组;若已存在返回 `false`。
pub fn Relation::insert(self : Relation, t : Tuple) -> Bool {
  if self.tuples.contains(t) {
    return false
  }
  self.tuples.add(t)
  if t.length() > 0 {
    let key = t.get(0)
    match self.idx0.get(key) {
      Some(set) => set.add(t)
      None => {
        let set = @hashset.HashSet([])
        set.add(t)
        self.idx0.set(key, set)
      }
    }
  }
  true
}

///|
/// 批量插入并返回新增数量。
pub fn Relation::insert_all(self : Relation, ts : Iter[Tuple]) -> Int {
  let mut added = 0
  for t in ts {
    if self.insert(t) {
      added = added + 1
    }
  }
  added
}

///|
/// 遍历全部元组。
pub fn Relation::iter(self : Relation) -> Iter[Tuple] {
  self.tuples.iter()
}

///|
/// 按首参数精确查找(利用首参数索引)。
pub fn Relation::lookup0(self : Relation, v : Value) -> Iter[Tuple] {
  match self.idx0.get(v) {
    Some(set) => set.iter()
    None => Iter::empty()
  }
}

///|
/// 元组是否已存在。
pub fn Relation::contains(self : Relation, t : Tuple) -> Bool {
  self.tuples.contains(t)
}

///|
/// 移除全部元组(用于分层求值前的重置)。
pub fn Relation::clear(self : Relation) -> Unit {
  self.tuples.clear()
  self.idx0.clear()
}

///|
/// 以确定顺序输出所有元组(字典序)。
pub fn Relation::to_string(self : Relation) -> String {
  let arr : Array[Tuple] = []
  for t in self.tuples {
    arr.push(t)
  }
  arr.sort()
  let b = StringBuilder::new()
  b.write_char('{')
  let mut first = true
  for t in arr {
    if first {
      first = false
    } else {
      b.write_string(", ")
    }
    b.write_string(t.to_string())
  }
  b.write_char('}')
  b.to_string()
}