///|
pub fn patch_info(
  record : VcfRecord,
  key : String,
  value : VcfValue,
) -> VcfRecord {
  let info : Array[(String, VcfValue)] = []
  let mut replaced = false
  for pair in record.info {
    if pair.0 == key {
      info.push((key, value))
      replaced = true
    } else {
      info.push(pair)
    }
  }
  if !replaced {
    info.push((key, value))
  }
  copy_record_with_info(record, info)
}

///|
pub fn patch_remove_info(record : VcfRecord, key : String) -> VcfRecord {
  copy_record_with_info(record, record.info.filter(fn(pair) { pair.0 != key }))
}

///|
pub fn patch_clear_info(record : VcfRecord) -> VcfRecord {
  copy_record_with_info(record, [])
}

///|
pub fn patch_qual(record : VcfRecord, qual : Double?) -> VcfRecord {
  copy_record(record, qual~)
}

///|
pub fn patch_filters(record : VcfRecord, filters : Array[String]) -> VcfRecord {
  copy_record(record, filters~)
}

///|
pub fn patch_ids(record : VcfRecord, ids : Array[String]) -> VcfRecord {
  copy_record(record, ids~)
}

///|
pub fn patch_position(
  record : VcfRecord,
  chrom : String,
  pos : Int,
) -> VcfRecord {
  copy_record(record, chrom~, pos~)
}

///|
pub fn patch_alt(record : VcfRecord, alts : Array[String]) -> VcfRecord {
  copy_record(record, alt_alleles=alts)
}

///|
pub fn patch_sample(record : VcfRecord, sample : SampleCall) -> VcfRecord {
  let samples : Array[SampleCall] = []
  let mut replaced = false
  for item in record.samples {
    if item.name == sample.name {
      samples.push(sample)
      replaced = true
    } else {
      samples.push(item)
    }
  }
  if !replaced {
    samples.push(sample)
  }
  copy_record(record, samples~)
}

///|
pub fn patch_sample_value(
  sample : SampleCall,
  key : String,
  value : VcfValue,
) -> SampleCall {
  let values : Array[(String, VcfValue)] = []
  let mut replaced = false
  for pair in sample.values {
    if pair.0 == key {
      values.push((key, value))
      replaced = true
    } else {
      values.push(pair)
    }
  }
  if !replaced {
    values.push((key, value))
  }
  { name: sample.name, values }
}

///|
fn copy_record(
  record : VcfRecord,
  chrom? : String = "",
  pos? : Int = -1,
  ids? : Array[String] = [],
  alt_alleles? : Array[String] = [],
  qual? : Double? = None,
  filters? : Array[String] = [],
  samples? : Array[SampleCall] = [],
) -> VcfRecord {
  {
    chrom: if chrom == "" {
      record.chrom
    } else {
      chrom
    },
    pos: if pos < 0 {
      record.pos
    } else {
      pos
    },
    ids: if ids.length() == 0 {
      record.ids
    } else {
      ids
    },
    ref_allele: record.ref_allele,
    alt_alleles: if alt_alleles.length() == 0 {
      record.alt_alleles
    } else {
      alt_alleles
    },
    qual,
    filters: if filters.length() == 0 {
      record.filters
    } else {
      filters
    },
    info: record.info,
    format_keys: record.format_keys,
    samples: if samples.length() == 0 {
      record.samples
    } else {
      samples
    },
  }
}

///|
fn copy_record_with_info(
  record : VcfRecord,
  info : Array[(String, VcfValue)],
) -> VcfRecord {
  {
    chrom: record.chrom,
    pos: record.pos,
    ids: record.ids,
    ref_allele: record.ref_allele,
    alt_alleles: record.alt_alleles,
    qual: record.qual,
    filters: record.filters,
    info,
    format_keys: record.format_keys,
    samples: record.samples,
  }
}