module TeamUtil

  # Get all matching method names out of definition.
  # A definition is a
  #   * simple string
  #   * regular expression
  #   * array of strings or regular expressions
  #   * symbol
  # _[String|Regexp|Array|Symbol]*_
  def get_all_method_names(baseclass, definition) 
    #return value
    result = nil
    if (definition.instance_of?(Array))
      #array of definitions? => concat all subsets
      result = Array.new
      #list of methods given
      definition.each { |methoddef|
        result.concat(get_all_method_names(baseclass, methoddef))
      }
    elsif (definition.instance_of?(String))
      #simple string? => 
      result = get_method_names(baseclass, /^#{Regexp.escape(definition)}$/)
    elsif (definition.instance_of?(Regexp))
      result = get_method_names(baseclass, definition)
    elsif (definition.instance_of?(Symbol))
      result = get_method_names(baseclass, /^#{Regexp.escape(definition.id2name)}$/)
    else
      raise ObjectTeam::TeamException, "How to handle type >#{definition.class.name}< in #{baseclass.name} callin source?", caller
    end
    return result
  end
  
  # Get all matching method names out of definition.
  # A definition is a string or a regexp.
  def get_method_names(baseclass, methodfilter)
    result = Hash.new
    #methodfilter = /^#{methodfilter}$/
    delegatefilter = /^#{Interceptor::PREFIX}/
    #use all methodnames defined by the class and by callin-bindings
    while (baseclass!=Object)
      #baseclass.public_instance_methods(false).concat(baseclass.callins.keys).each { |m|
      baseclass.public_instance_methods(false).each { |m|
        if (!delegatefilter.match(m) and methodfilter.match(m))
          result[m] = true
        end
      }
      baseclass = baseclass.superclass
    end
    #check for ctor
    #result["initialize"]=true if (methodfilter.match("initialize"))
    return result.keys
  end
end

class WeakReferenceError < StandardError
end
class WeakReference
  # the object id of the reference
  attr :oid

  # Construct a weak ref: reference by id not by pointer
  def initialize(obj)
    @oid = obj.__id__
    ObjectSpace.define_finalizer(obj, @@final)
    OIDS[@oid] = true
  end

  # Indicates, if this reference is alive.
  def alive?
    return OIDS[@oid]
  end

  # Get reference by pointer.
  def ref
    if alive?
      return ObjectSpace._id2ref(@oid)
    else
      raise WeakReferenceError, "Already recycled Object"
    end
  end

  # Static map of all weak reference.
  # GC will remove the relation.
  OIDS = {}
  @@final = lambda{ |id|
    old_status = Thread.critical
    Thread.critical = true
    begin
      OIDS.delete(id)
    ensure
      Thread.critical = old_status
    end
  }
end


# This class is an ordinary hash where no direct references are hold to the key.
# An entry in a WeakHash will automatically be removed when its key is no
# longer in ordinary use and finalized by the garbage collector.
class WeakHash
  # encapsulate a real hash
  attr :hash

  # Create a new Weak hash.
  def initialize()
    @hash = {}
    # GC will remove the relation.
    @final = lambda{ |id|
      old_status = Thread.critical
      Thread.critical = true
      begin
        self.hash.delete(id)
      ensure
        Thread.critical = old_status
      end
    }
  end

  #Return len of hash.
  def length
    @hash.length
  end
  alias_method(:size, :length)

  # Iterate over all valid key, value pairs.
  # [block] the block to execute
  def each(&block)
    @hash.each{ |key, val|
      block.call(ObjectSpace._id2ref(key), val)
    }
  end

  # Get value of the given key
  # [key] the key to lookup for a value
  # [return] the stored value or nil, if not found.
  def fetch(key)
    @hash[key.__id__]
  end
  alias_method(:[], :fetch)

  # Store a key => value pair. 
  # This hash do not hold a direct reference to the key.
  # The pair gets lost, if the key gets finalized.
  # [key] the key to lookup the stored value
  # [value] the value to store
  def store(key, value)
    ObjectSpace.define_finalizer(key, @final)
    @hash.store(key.__id__, value)
  end
  alias_method(:[]=, :store)

  # Implement equality operator.
  def ==(other)
    if (other.instance_of?(WeakHash))
      return (@hash == other.hash)
    else
      return (@hash == other)
    end
  end
end

if (__FILE__ == $0)
  def test(whash)
    whash.each { |key, val|
      puts "Have key #{key} => #{val}"
    }
  end
    
  weakhash = WeakHash.new
  #create some keys
  key1 = "One Test"
  key2 = "Another Test"
  key3 = "The ultimate Test"
  #fill hash
  weakhash[key1] = "check"
  weakhash[key2] = "check"
  weakhash[key3] = "check"
  
  #first check => behave as usual hash
  ObjectSpace.garbage_collect
  print "\n\nthree items should be visible:\n"
  test(weakhash)

  #second check => perhaps three items should be visible
  key1 = nil
  key2 = nil
  key3 = nil
  print "\n\n__perhaps__! three items could be visible (with respect to GC):\n"
  test(weakhash)

  #third check => no item should be visible!
  ObjectSpace.garbage_collect
  print "\n\nall items should be finalized!\n"
  test(weakhash)
end

