# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
# License:   Apache License, Version 2.0

module RTM::AR::IO
  # XTM2 Export.
  # Each Topic Maps Construct gets a to_xtm2 method.
  # The result is a REXML::Element except for TopicMap where it is a REXML::Document.
  module TOXTM2
    require 'rexml/document'
    def self.scope(scope)
      res = REXML::Element.new('scope')
      scope.each do |s|
        res << s.to_xtm2_ref
      end
      res
    end
    def self.type(type)
      res = REXML::Element.new('type')
      res << type.to_xtm2_ref
      res
    end
    def self.value(datatype, value)
      if datatype == RTM::PSI[:IRI]
        res = REXML::Element.new 'resourceRef'
        res.add_attribute('href', value)
      else
        res = REXML::Element.new 'resourceData'
        res.add_attribute('datatype', datatype) if datatype
        res.text = value
      end
      res
    end
    def self.locator(loc, tagname = "itemIdentity")
      x = REXML::Element.new(tagname)
      x.add_attribute('href',loc.to_s) # loc could be Locator or String, to_s serves both
      x
    end

    module TopicMap
      # returns the XTM 2.0 representation of this topic map as an REXML::Document, ready for outputting
      def to_xtm2
        # topicMap = element topicMap { reifiable, version, mergeMap*,
        #                               (topic | association)* }
        doc = REXML::Document.new
        doc << REXML::XMLDecl.new
        x = doc.add_element 'topicMap', {'xmlns' => 'http://www.topicmaps.org/xtm/', 'version' => '2.0'}
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        x << REXML::Comment.new("Topics count: #{topics.size}")
        x << REXML::Comment.new("Associations count: #{associations.size}")
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        # mergeMap not used
        topics.each { |t| x << t.to_xtm2 }
        associations.each { |a| x << a.to_xtm2 }
        doc
      end
    end

    module Topic
      # this is a helper-method for the to_xtm2 amd to_xtm2_ref methods
      def xtm2_id
        "t#{id}"
      end
      # returns the XTM 2.0 representation of this topic as an REXML::Element
      def to_xtm2
        #topic = element topic { id,
        #                    (itemIdentity | subjectLocator | subjectIdentifier)*,
        #                    instanceOf?, (name | occurrence)* }
        x = REXML::Element.new('topic')
        x.add_attribute('id', xtm2_id )
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        subject_identifiers.each { |si| x << TOXTM2.locator(si, "subjectIdentifier") } # subjectIdentifier
        if item_identifiers.empty? && subject_identifiers.empty?
          TOXTM2.locator(xtm2_id) # itemIdentity
        end
        subject_locators.each { |sl| x << TOXTM2.locator(sl, "subjectLocator") } # subjectLocator
        # I guess we won't create instanceOf-Elements but instead type-instance associations.
        names.each { |n| x << n.to_xtm2 }
        occurrences.each { |o| x << o.to_xtm2 }
        x
      end
      # returns the an (internal) XTM 2.0 reference to this topic
      def to_xtm2_ref
        x = REXML::Element.new 'topicRef'
        x.add_attribute('href', "##{xtm2_id}")
        x
      end
    end

    module Association
      # returns the XTM 2.0 representation of this association as an REXML::Element
      def to_xtm2
        warn("TOXTM2: Warning: outputting invalid Association #{self}") unless valid?
        # association = element association { reifiable, type, scope?, role+ }
        x = REXML::Element.new 'association'
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        x << TOXTM2.type(type) if type
        x << TOXTM2.scope(scope) unless scope.empty?
        roles.each { |r| x << r.to_xtm2 }
        x
      end
    end

    module TopicName
      def to_xtm2
        warn("TOXTM2: Warning: outputting invalid TopicName #{self}") unless valid?
        # name = element name { reifiable, type?, scope?, value, variant* }
        x = REXML::Element.new 'name'
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        x << TOXTM2.type(type) if type
        x << TOXTM2.scope(scope) unless scope.empty?
        (x << REXML::Element.new('value')).text = value # adds the value within a value-element
        variants.each { |v| x << v.to_xtm2 }
        x
      end
    end

    module Occurrence
      def to_xtm2
        warn("TOXTM2: Warning: outputting invalid Occurrence #{self}") unless valid?
        # occurrence = element occurrence { reifiable,
        #   type, scope?, ( resourceRef | resourceData ) }
        x = REXML::Element.new 'occurrence'
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        x << TOXTM2.type(type) if type
        x << TOXTM2.scope(scope) unless scope.empty?
        x << TOXTM2.value(datatype, value)
        x
      end
    end

    module AssociationRole
      def to_xtm2
        warn("TOXTM2: Warning: outputting invalid AssociationRole #{self}") unless valid?
        # role = element role { reifiable, type, topicRef }
        x = REXML::Element.new 'role'
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        x << TOXTM2.type(type) if type
        x << player.to_xtm2_ref if player
        x
      end
    end

    module Variant
      def to_xtm2
        warn("TOXTM2: Warning: outputting invalid Variant #{self}") unless valid?
        # variant = element variant { reifiable, scope, (resourceRef | resourceData) }
        x = REXML::Element.new 'variant'
        x.add_attribute('reifier', reifier.xtm2_id) if reifier
        item_identifiers.each { |ii| x << TOXTM2.locator(ii) } # itemIdentity
        x << TOXTM2.scope(scope)
        x << TOXTM2.value(datatype, value)
        x
      end
    end
  
    RTM::AR.register_extension self 
  end
end