class Metanorma::Generic::Converter

def baselocation(loc)

def baselocation(loc)
  loc.nil? and return nil
  loc
end

def bibdata_hash(xmldoc)

def bibdata_hash(xmldoc)
  b = xmldoc.at("//bibdata") || xmldoc.at("//xmlns:bibdata")
  BibdataConfig.from_xml("<metanorma>#{b.to_xml}</metanorma>")
    .bibdata.to_hash
end

def bibdata_validate(doc)

def bibdata_validate(doc)
  stage_validate(doc)
  committee_validate(doc)
end

def blank_method(*args); end

def blank_method(*args); end

def boilerplate_file(xmldoc)

def boilerplate_file(xmldoc)
  f = configuration.boilerplate
  f.nil? and return super
  f.is_a? String and return baselocation(f)
  f.is_a? Hash and f[@lang] and return baselocation(f[@lang])
  super
end

def boilerplate_isodoc(xmldoc)

def boilerplate_isodoc(xmldoc)
  conv = super or return nil
  Metanorma::Generic::Configuration::CONFIG_ATTRS.each do |a|
    conv.meta.set(a, configuration.send(a))
  end
  #conv.meta.set(:bibdata, bibdata_hash(xmldoc))
  conv
end

def committee_validate(xmldoc)

def committee_validate(xmldoc)
  committees = Array(configuration&.committees) || return
  committees.empty? and return
  xmldoc.xpath("//bibdata/ext/editorialgroup/committee").each do |c|
    committees.include? c.text or
      @log.add("Document Attributes", nil,
               "#{c.text} is not a recognised committee")
  end
end

def configuration

def configuration
  Metanorma::Generic.configuration
end

def content_validate(doc)

def content_validate(doc)
  super
  bibdata_validate(doc.root)
end

def default_publisher

def default_publisher
  configuration.organization_name_long
end

def doc_converter(node)

def doc_converter(node)
  IsoDoc::Generic::WordConvert.new(doc_extract_attributes(node))
end

def docidentifier_cleanup(xmldoc)

def docidentifier_cleanup(xmldoc)
  docid = xmldoc.at("//bibdata/docidentifier") or return
  docid.text.empty? or return
  id = docidentifier_from_template(xmldoc) or return
  (id.empty? and docid.remove) or docid.children = id
end

def docidentifier_from_template(xmldoc)

def docidentifier_from_template(xmldoc)
  b = boilerplate_isodoc(xmldoc) or return
  template = configuration.docid_template ||
    "{{ organization_name_short }} {{ docnumeric }}"
  b.populate_template(template, nil)
end

def doctype(node)

def doctype(node)
  d = super
  node.attr("doctype") == "article" and d = "article"
  a = configuration.default_doctype and @default_doctype = a
  configuration.doctypes or
    return d == "article" ? @default_doctype : d
  type = @default_doctype || configuration.doctypes.keys[0]
  if !configuration.doctypes.key?(d)
    node.attr("doctype") && node.attr("doctype") != "article" and # factory default
      @log.add("Document Attributes", nil,
               "#{d} is not a legal document type: reverting to '#{type}'")
    d = type
  end
  d
end

def document(node)

def document(node)
  if node.attr("customize")
    p = node.attr("customize")
    (Pathname.new p).absolute? or
      p = File.expand_path(File.join(Metanorma::Utils::localdir(node), p))
    read_config_file(p)
  end
  super
end

def empty_metadata_cleanup(ext)

Process elements in reverse doc order to handle nested removals properly
Keep cleaning until no more elements are removed (recursive depth-first)
def empty_metadata_cleanup(ext)
  loop do
    removed_count = 0
    ext.xpath(".//*").reverse_each do |element|
      element.children.empty? && element.attributes.empty? or next
      element.remove
      removed_count += 1
    end
    removed_count.zero? and break # Stop when no elems removed this pass
  end
end

def html_converter(node)

def html_converter(node)
  IsoDoc::Generic::HtmlConvert.new(html_extract_attributes(node))
end

def metadata_committee(node, xml)

def metadata_committee(node, xml)
  node.attr("committee") or return
  xml.editorialgroup do |a|
    a.committee node.attr("committee"),
                **attr_code(type: node.attr("committee-type"))
    i = 2
    while node.attr("committee_#{i}")
      a.committee node.attr("committee_#{i}"),
                  **attr_code(type: node.attr("committee-type_#{i}"))
      i += 1
    end
  end
end

def metadata_doctype(node, xml)

def metadata_doctype(node, xml)
  d = doctype(node)
  xml.doctype d, attr_code(abbreviation: configuration&.doctypes&.dig(d))
end

def metadata_ext(node, ext)

def metadata_ext(node, ext)
  super
  if configuration.metadata_extensions.is_a? Hash
    metadata_ext_hash(node, ext, configuration.metadata_extensions)
  else
    Array(configuration.metadata_extensions).each do |e|
      a = node.attr(e) and ext.send e, a
    end
  end
  empty_metadata_cleanup(ext.parent)
end

def metadata_ext_attrs(hash, node)

def metadata_ext_attrs(hash, node)
  return {} unless hash.is_a?(Hash)
  ret = {}
  hash.each do |k, v|
    next unless v.is_a?(Hash) && v["_attribute"]
    ret[(v["_output"] || k).to_sym] = node.attr(k)
  end
  ret
end

def metadata_ext_hash(node, ext, hash)

def metadata_ext_hash(node, ext, hash)
  hash.each do |k, v|
    EXT_STRUCT.include?(k) || (!v.is_a?(Hash) && !node.attr(k)) and next
    if v.is_a?(Hash) && v["_list"]
      csv_split(node.attr(k), ",").each do |val|
        metadata_ext_hash1(k, val, ext, v, node)
      end
    else
      metadata_ext_hash1(k, node.attr(k), ext, v, node)
    end
  end
end

def metadata_ext_hash1(key, value, ext, hash, node)

def metadata_ext_hash1(key, value, ext, hash, node)
  h = hash.is_a?(Hash)
  h && hash["_attribute"] and return
  is_hash = h && !hash.keys.reject { |n| EXT_STRUCT.include?(n) }.empty?
  !is_hash && (value.nil? || value.empty?) and return
  name = h ? (hash["_output"] || key) : key
  ext.send name, **attr_code(metadata_ext_attrs(hash, node)) do |e|
    is_hash ? metadata_ext_hash(node, e, hash) : (e << value)
  end
end

def metadata_id(node, xml)

def metadata_id(node, xml)
  xml.docidentifier primary: "true",
                    type: configuration.organization_name_short do |i|
    i << (node.attr("docidentifier") || "")
  end
end

def metadata_status(node, xml)

def metadata_status(node, xml)
  xml.status do |s|
    s.stage ( node.attr("status") || node.attr("docstage") ||
             configuration.default_stage || "published")
    x = node.attr("substage") and s.substage x
    x = node.attr("iteration") and s.iteration x
  end
end

def org_abbrev

def org_abbrev
  if !configuration.organization_name_long.empty? &&
      !configuration.organization_name_short.empty? &&
      configuration.organization_name_long !=
          configuration.organization_name_short
    { configuration.organization_name_long =>
      configuration.organization_name_short }
  else
    super
  end
end

def outputs(node, ret)

def outputs(node, ret)
  File.open("#{@filename}.xml", "w:UTF-8") { |f| f.write(ret) }
  presentation_xml_converter(node)&.convert("#{@filename}.xml")
  html_converter(node)&.convert("#{@filename}.presentation.xml",
                                nil, false, "#{@filename}.html")
  doc_converter(node)&.convert("#{@filename}.presentation.xml",
                               nil, false, "#{@filename}.doc")
  pdf_converter(node)&.convert("#{@filename}.presentation.xml",
                               nil, false, "#{@filename}.pdf")
end

def presentation_xml_converter(node)

def presentation_xml_converter(node)
  IsoDoc::Generic::PresentationXMLConvert
    .new(html_extract_attributes(node)
    .merge(output_formats: ::Metanorma::Generic::Processor.new
    .output_formats))
end

def read_config_file(path_to_config_file)

def read_config_file(path_to_config_file)
  Metanorma::Generic.configuration
    .set_default_values_from_yaml_file(path_to_config_file)
  # reregister Processor to Metanorma with updated values
  if defined? Metanorma::Registry
    Metanorma::Registry.instance.register(Metanorma::Generic::Processor)
  end
end

def relaton_relations

def relaton_relations
  Array(configuration.relations) || []
end

def schema_file

def schema_file
  configuration.validate_rng_file || "generic.rng"
end

def schema_location

def schema_location
  baselocation(configuration.validate_rng_file) ||
    File.join(File.dirname(__FILE__), "generic.rng")
end

def sections_cleanup(xml)

def sections_cleanup(xml)
  super
  xml.xpath("//*[@inline-header]").each do |h|
    h.delete("inline-header")
  end
end

def sectiontype_streamline(ret)

def sectiontype_streamline(ret)
  if configuration.termsdefs_titles&.map(&:downcase)&.include? ret
    "terms and definitions"
  elsif configuration.symbols_titles&.map(&:downcase)&.include? ret
    "symbols and abbreviated terms"
  elsif configuration.normref_titles&.map(&:downcase)&.include? ret
    "normative references"
  elsif configuration.bibliography_titles&.map(&:downcase)&.include? ret
    "bibliography"
  else
    super
  end
end

def stage_validate(xmldoc)

def stage_validate(xmldoc)
  stages = configuration.stage_abbreviations&.keys || return
  stages.empty? and return
  stage = xmldoc.at("//bibdata/status/stage")&.text
  stages.include? stage or
    @log.add("Document Attributes", nil,
             "#{stage} is not a recognised status")
end