require "relaton/element_finder"

module Relaton
  class Bibcollection
    extend Relaton::ElementFinder

    ATTRIBS = %i[
      title
      items
      doctype
      author
    ]

    attr_accessor *ATTRIBS

    def initialize(options)
      self.items = []
      ATTRIBS.each do |k|
        value = options[k] || options[k.to_s]
        self.send("#{k}=", value)
      end
      self.items = (self.items || []).inject([]) do |acc,item|
        acc << if item.is_a?(::Relaton::Bibcollection) ||
          item.is_a?(::Relaton::Bibdata)
          item
        else
          new_bib_item_class(item)
        end
      end
      self
    end

    # arbitrary number, must sort after all bib items
    def doc_number
      9999999
    end

    def self.from_xml(source)
      title = find_text("./relaton-collection/title", source)
      author = find_text("./relaton-collection/contributor[role/@type = 'author']/organization/name", source)

      items = find_xpath("./relaton-collection/relation", source)&.map do |item|
        bibdata = find("./bibdata", item)
        klass = bibdata ? Bibdata : Bibcollection
        klass.from_xml(bibdata || item)
      end

      new(title: title, author: author, items: items)
    end

    def new_bib_item_class(options)
      if options["items"]
        ::Relaton::Bibcollection.new(options)
      else
        ::Relaton::Bibdata.new(options)
      end
    end

    def items_flattened
      items.sort_by! do |b|
        b.doc_number
      end

      items.inject([]) do |acc,item|
        if item.is_a? ::Relaton::Bibcollection
          acc << item.items_flattened
        else
          acc << item
        end
      end
    end

    def to_xml
      items.sort_by! do |b|
        b.doc_number
      end

      collection_type = if doctype
        "type=\"#{doctype}\""
      else
        'xmlns="https://open.ribose.com/relaton-xml"'
      end

      ret = "<relaton-collection #{collection_type}>"
      ret += "<title>#{title}</title>" if title
      if author
        ret += "<contributor><role type='author'/><organization><name>#{author}</name></organization></contributor>"
      end
      unless items.empty?
        items.each do |item|
          ret += "<relation type='partOf'>"
          ret += item.to_xml
          ret += "</relation>\n"
        end
      end
      ret += "</relaton-collection>\n"
    end

    def to_yaml
      to_h.to_yaml
    end

    def to_h
      items.sort_by! do |b|
        b.doc_number
      end

      a = ATTRIBS.inject({}) do |acc, k|
        acc[k.to_s] = send(k)
        acc
      end

      a["items"] = a["items"].map(&:to_h)

      { "root" => a }
    end

  end
end