module Metanorma::Utils

def anchor_or_uuid(node = nil)

def anchor_or_uuid(node = nil)
  uuid = UUIDTools::UUID.random_create
  node.nil? || node.id.nil? || node.id.empty? ? "_" + uuid : node.id
end

def asciidoc_sub(x)

def asciidoc_sub(x)
  return nil if x.nil?
  return "" if x.empty?
  d = Asciidoctor::Document.new(x.lines.entries, { header_footer: false, backend: :html })
  b = d.parse.blocks.first
  b.apply_subs(b.source)
end

def endash_date(elem)

def endash_date(elem)
  elem.traverse do |n|
    n.text? and n.replace(n.text.gsub(/\s+--?\s+/, "–").gsub(/--/, "–"))
  end
end

def flatten_rawtext(node)

and extract only raw text
if node contains blocks, flatten them into a single line;
not currently used
def flatten_rawtext(node)
  result = []
  if node.respond_to?(:blocks) && node.blocks?
    node.blocks.each { |b| result << flatten_rawtext(b) }
  elsif node.respond_to?(:lines)
    result = flatten_rawtext_lines(node, result)
  elsif node.respond_to?(:text)
    result << node.text.gsub(/<[^>]*>+/, "")
  else
    result << node.content.gsub(/<[^>]*>+/, "")
  end
  result.reject(&:empty?)
end

def flatten_rawtext_lines(node, result)

not currently used
def flatten_rawtext_lines(node, result)
  node.lines.each do |x|
    if node.respond_to?(:context) && (node.context == :literal ||
        node.context == :listing)
      result << x.gsub(/</, "&lt;").gsub(/>/, "&gt;")
    else
      # strip not only HTML <tag>, and Asciidoc xrefs <<xref>>
      result << x.gsub(/<[^>]*>+/, "")
    end
  end
  result
end

def localdir(node)

def localdir(node)
  docfile = node.attr("docfile")
  docfile.nil? ? './' : Pathname.new(docfile).parent.to_s + '/'
end

def set_nested_value(hash, keys, new_val)

mod from https://stackoverflow.com/a/42425884
Set hash value using keys path
def set_nested_value(hash, keys, new_val)
  key = keys[0]
  if keys.length == 1
    hash[key] = hash[key].is_a?(Array) ?  (hash[key] << new_val) :
      hash[key].nil? ?  new_val : [hash[key], new_val]
  else
    if hash[key].is_a?(Array)
      hash[key][-1] = {} if !hash[key].empty? && hash[key][-1].nil?
      hash[key] << {} if hash[key].empty? || !hash[key][-1].is_a?(Hash)
      set_nested_value(hash[key][-1], keys[1..-1], new_val)
    elsif hash[key].nil? || hash[key].empty?
      hash[key] = {}
      set_nested_value(hash[key], keys[1..-1], new_val)
    elsif hash[key].is_a?(Hash) && !hash[key][keys[1]]
      set_nested_value(hash[key], keys[1..-1], new_val)
    elsif !hash[key][keys[1]]
      hash[key] = [hash[key], {}]
      set_nested_value(hash[key][-1], keys[1..-1], new_val)
    else
      set_nested_value(hash[key], keys[1..-1], new_val)
    end
  end
  hash
end

def smartformat(n)

TODO needs internationalisation
def smartformat(n)
  n.gsub(/ --? /, "&#8201;&#8212;&#8201;").
    gsub(/--/, "&#8212;").smart_format.gsub(/</, "&lt;").gsub(/>/, "&gt;")
end

def svgmap_rewrite(xmldoc, localdir = "")

def svgmap_rewrite(xmldoc, localdir = "")
  xmldoc.xpath("//svgmap").each do |s|
    next unless src = s.at(".//image/@src")
    path = File.file?(src) ? src : localdir + src
    File.file?(path) or next
    svg = Nokogiri::XML(File.read(path, encoding: "utf-8"))
    svgmap_rewrite1(s, svg, path)
    next if s.at("./target/eref")
    s.replace(s.at("./figure"))
  end
end

def svgmap_rewrite1(s, svg, path)

def svgmap_rewrite1(s, svg, path)
  targets = s.xpath("./target").each_with_object({}) do |t, m|
    x = t.at("./xref") and m[t["href"]] = "##{x['target']}"
    x = t.at("./link") and m[t["href"]] = x['target']
    t.remove if t.at("./xref | ./link")
  end
  svg.xpath(".//xmlns:a").each do |a|
    x = targets[a["xlink:href"]] and a["xlink:href"] = x
  end
  File.open(path, "w", encoding: "utf-8") { |f| f.write(svg.to_xml) }
end

def to_ncname(s)

def to_ncname(s)
  start = s[0]
  ret1 = %r([#{NAMECHAR}#]).match(start) ? "_" :
    (%r([#{NAMESTARTCHAR}#]).match(start) ? "_#{start}" : start)
  ret2 = s[1..-1] || ""
  ret = (ret1 || "") + ret2.gsub(%r([#{NAMECHAR}#]), "_")
  ret
end