# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig. # License: Apache License, Version 2.0 module RTM::AR class TMSetDelegator < TMDelegator include Enumerable # attr_reader :content_class_name def initialize(obj,parent,type) @obj = obj @parent = parent @type = type end # This class method wraps a Set completely while the instance method wraps one single contained object def self.wrap(obj, parent=nil, type=nil) return nil unless obj raise "Double wrapping" if obj.respond_to?(:__getobj__) self.new(obj, parent, type) end def add(obj) return unless obj old = @obj.detect { |x| x == obj } # can't that be done easier? if old old.merge obj else if obj.respond_to? :__getobj__ @obj << obj.__getobj__ else case @type when :Topic @obj << @parent.topic_map.get!(obj).__getobj__ @parent.__getobj__.reload when :ItemIdentifier if @parent.class.name.to_s =~ /::Topic$/ tbi = @parent.topic_map._item_identifier(obj) if tbi && tmc=tbi.topic_map_construct if tmc.class.name =~ /::Topic$/ return @parent if tmc == @parent.__getobj__ result = Topic.wrap(tmc).merge @parent return result else raise "Duplicate Item Identifier" end end tbsi = @parent.topic_map._subject_identifier(obj.to_s) if tbsi if t=tbsi.topic return @parent if t == @parent.__getobj__ result = Topic.wrap(t).merge @parent # after merging, we still need to add the II result.__getobj__.item_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id) return result end end end result = @obj << @parent.topic_map._item_identifier!(obj.to_s) return result when :SubjectIdentifier # check for existing item identifier puts puts "trying to add SI to a topic" tbi = @parent.topic_map._item_identifier(obj) if tbi && tmc=tbi.construct puts "something with this II exists" if tmc.class.name =~ /::Topic$/ puts "it exists as a topic" puts tmc == @parent.__getobj__ return @parent if tmc == @parent.__getobj__ puts "trying to merge" puts "BEFORE" begin result = Topic.wrap(tmc).merge(@parent) rescue Exception => e puts e.inspect raise e end puts "AFTER" puts "done merging, now adding SI" #result = @parent.merge(Topic.wrap(tmc)) # after merging, we still need to add the SI result.__getobj__.subject_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id) puts "done adding SI, now reloading" result.reload puts "done reloading" return result else warn("This subject identifier IRI already belongs to another topic map construct (not a topic)") end end puts "checking for existing SI" # check for existing subject identifier tbsi = @parent.topic_map._subject_identifier(obj.to_s) if tbsi puts "SI exists" if true && t=tbsi.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning return @parent if t == @parent.__getobj__ result = Topic.wrap(t).merge @parent return result end end @obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id) when :SubjectLocator tbsl = @parent.topic_map._subject_locator(obj.to_s) if tbsl if true && t=tbsl.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning return @parent if t == @parent.__getobj__ result = Topic.wrap(t).merge @parent return result end end @obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id) end end end end alias :<< :add def add_all(objs) return unless objs objs.each {|obj| add(obj)} true end def each(&b) @obj.each { |e| yield wrap(e)} end def size @obj.size end alias :length :size def empty? @obj.empty? end def delete(obj) obj = obj.__getobj__ if obj.respond_to? :__getobj__ case @type when :ItemIdentifier, :SubjectIdentifier, :SubjectLocator obj = @obj.find_by_reference(@parent.topic_map.resolve(obj.to_s)) if obj.is_a? String when :Topic obj = @parent.topic_map.get!(obj).__getobj__ end @obj.delete(obj) # item_identifiers: remove also from topicMap #removed_event obj if respond_to? :removed_event end alias :remove :delete def include?(obj) return @obj.include?(obj.__getobj__) #@obj.each { |e| return true if e == obj } # T#ODO support for get #false end def first wrap(@obj.entries.first) end def last wrap(@obj.entries.last) end def to_s "[#{@obj.entries.map { |e| wrap(e).to_s }.join(", ") }]" end def [](i) wrap(@obj[i]) end def content_class # @content_class ||= RTM.const_get(@content_class_name) @content_class ||= RTM.const_get("#{@content_class_name}MemImpl") end def find(*args) res = @obj.find(*args) if res.respond_to? :each Constructs.wrap(res) else Construct.wrap(res) end end def &(other) @obj.to_a & other.to_a end alias :old_method_missing :method_missing def method_missing(method_name, *args) if @obj.size > 0 && first.respond_to?(method_name) && (![:__getobj__, :__setobj__].include?(method_name)) a = [] inject(a) {|all,single| all << single.send(method_name, *args)} a else old_method_missing(method_name, *args) end end alias :old_respond_to? :respond_to? def respond_to?(method_name) resp = old_respond_to?(method_name) return resp if resp # i.e. if true return false if [:__getobj__, :__setobj__].include?(method_name) # ... and ask first child otherwise @obj.size > 0 && first.respond_to?(method_name) end def ==(x) self.to_a == x.to_a end # TMSetDelegator#to_a doesn't help as thought, but maybe we come back to that l8r... #def to_a # @obj.map {|o| wrap(o)} #end end end