$__TRAIT_DEBUG__ = ENV['__TRAIT_DEBUG__'] || ENV['TRAIT_DEBUG']

class Object
#--{{{
  def singleton_method_added(*a, &b)
#--{{{
    obj = self
    obj.__trait_singleton_class.__trait_module_eval{ @__trait_singleton_super = obj }
#--}}}
  end
  def __trait_singleton_class
#--{{{
    @__trait_singleton_class ||= class << self;self;end
#--}}}
  end
  def __trait_singleton?
#--{{{
    @__is_trait_singleton ||= 
      ((Class === self) and (@__is_trait_singleton ||= (not self.ancestors.include?(self))))
#--}}}
  end
  def __trait_search_path
#--{{{
    #((Class === self and not __trait_singleton?) ? ancestors : [self])
    (__trait_singleton? or not respond_to? 'ancestors') ? [self] : ancestors
#--}}}
  end
  def __trait_arg_filter(*args, &block)
#--{{{
    pre = nil
    post = nil
    validate = nil
    default = nil
    names_and_defaults = nil

    if block and not block.respond_to? :__trait_default
      block.__trait_singleton_class.class_eval{ attr '__trait_default' }
    end

    list, hashes = [ args ].flatten.partition{|arg| not Hash === arg}
    opts = hashes.inject({}){|accum,h| accum.update h}

    getopt = lambda do |key|
      return opts.delete(key) if opts.has_key? key
      key = "#{ key }"
      return opts.delete(key) if opts.has_key? key
      key = key.intern
      return opts.delete(key) if
      opts.has_key? key
      return default
    end
    
    pre = getopt['pre']
    post = getopt['post']
    validate = getopt['validate']
    default = getopt['default']

    names_and_defaults = opts

    raise ArgumentError, 
      "cannot specify both 'default' keyword and 'default' block" if
        block and default

    default ||= block

    list.each{|name| names_and_defaults[name] = default}

    names = list + (names_and_defaults.keys - list)
    hooks = {'pre' => pre, 'post' => post, 'validate' => validate}
    names_and_hooks = names.inject({}){|h, name| h.update name => hooks}

    {
      'names' => names,
      'names_and_defaults' => names_and_defaults,
      'names_and_hooks' => names_and_hooks,
      'hooks' => {'pre' => pre, 'post' => post, 'validate' => validate},
      'pre' => pre, 'post' => post, 'validate' => validate,
      'default' => default,
    }
#--}}}
  end
  def __trait_instance_method_list
#--{{{
    @__trait_instance_method_list ||= {'writers' => [], 'readers' => [], }
#--}}}
  end
  def __trait_singleton_method_list
#--{{{
    @__trait_singleton_method_list ||= {'writers' => [], 'readers' => [], }
#--}}}
  end
  def __trait_instance_method_defaults
#--{{{
      @__trait_instance_method_defaults ||= {}
#--}}}
  end
  def __trait_singleton_method_defaults
#--{{{
      @__trait_singleton_method_defaults ||= {} 
#--}}}
  end


  def __trait_instance_method_hooks
#--{{{
      @__trait_instance_method_hooks ||= 
        Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil} }
#--}}}
  end
  def __trait_singleton_method_hooks
#--{{{
      @__trait_singleton_method_hooks ||= 
        Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil} }
#--}}}
  end
  def __trait_evaluate(*a, &b)
#--{{{
    ret, sent = nil
    loop do
      m = "__trait_evaluate__#{ Thread::current.object_id.abs }__#{ rand 666 }__#{ rand 42 }__"
      begin
        __trait_singleton_class.module_eval{ define_method m, &b }
        ret = send(sent = m, *a)
      ensure
        begin
          __trait_singleton_class.module_eval{ remove_method m }
        ensure
          break if sent
        end
      end
    end
    ret
#--}}}
  end


  def __trait_define_singleton_reader_traits(*args, &block)
#--{{{
    argf = __trait_arg_filter args, &block
    defaults = __trait_singleton_method_defaults
    list = __trait_singleton_method_list 
    mhooks = __trait_singleton_method_hooks
    argf['names_and_defaults'].each do |name, default|
      __trait_singleton_class.__trait_define_reader_trait name, default, defaults, list
    end
    argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
    __trait_search_path.map{|ta| ta.__trait_singleton_method_list['readers']}.flatten
#--}}}
  end
  def __trait_define_singleton_writer_traits(*args, &block)
#--{{{
    argf = __trait_arg_filter args, &block
    defaults = __trait_singleton_method_defaults
    list = __trait_singleton_method_list 
    mhooks = __trait_singleton_method_hooks
    argf['names_and_defaults'].each do |name, default|
      __trait_singleton_class.__trait_define_writer_trait name, default, defaults, list
    end
    argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
    __trait_search_path.map{|ta| ta.__trait_singleton_method_list['writers']}.flatten
#--}}}
  end
  def __trait_define_singleton_traits(*args, &block)
#--{{{
    writers = __trait_define_singleton_writer_traits(*args, &block)
    readers = __trait_define_singleton_reader_traits(*args, &block)
    [readers, writers] 
#--}}}
  end
  %w( 
      instance_reader_traits
      instance_reader_trait
      reader_traits
      reader_trait
      r_traits
      r_trait
      has_readers
      has_reader
      has_r

      instance_writer_traits
      instance_writer_trait
      writer_traits
      writer_trait
      w_traits
      w_trait
      has_writers
      has_writer
      has_w

      instance_traits
      instance_trait
      traits
      trait
      has
    ).each do |meth|
      eval <<-def
        def #{ meth }(*a, &b)
          __trait_singleton_class.send('#{ meth }', *a, &b)
        end
      def
    end
#--}}}
end
class Class
#--{{{
  def __trait_singleton_super
#--{{{
    class_eval{ def __________trait_singleton_super_init;end } unless defined? @__trait_singleton_super
    @__trait_singleton_super
#--}}}
  end
#--}}}
end
class Module 
#--{{{

  def __trait_module_eval(*a, &b)
#--{{{
    begin
      module_eval(*a, &b)
    rescue Exception => e
      STDERR.puts([a, b].inspect) if $__TRAIT_DEBUG__
      raise
    end
#--}}}
  end

  def __trait_define_instance_reader_traits(*args, &block)
#--{{{
    if __trait_singleton?
      return(__trait_singleton_super.__trait_define_singleton_reader_traits(*args, &block))
    end
    argf = __trait_arg_filter args, &block
    defaults = __trait_instance_method_defaults
    list = __trait_instance_method_list 
    mhooks = __trait_instance_method_hooks
    argf['names_and_defaults'].each do |name, default|
      __trait_define_reader_trait name, default, defaults, list
    end
    argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
    __trait_search_path.map{|ta| ta.__trait_instance_method_list['readers']}.flatten
#--}}}
  end
  %w( 
      instance_reader_traits
      instance_reader_trait
      reader_traits
      reader_trait
      rtraits
      rtrait
      r_traits
      r_trait
      has_readers
      has_reader
      has_r
    ).each{|meth| alias_method meth, '__trait_define_instance_reader_traits'}

  def __trait_define_instance_writer_traits(*args, &block)
#--{{{
    if __trait_singleton?
      return(__trait_singleton_super.__trait_define_singleton_writer_traits(*args, &block))
    end
    argf = __trait_arg_filter args, &block
    defaults = __trait_instance_method_defaults
    list = __trait_instance_method_list 
    mhooks = __trait_instance_method_hooks
    argf['names_and_defaults'].each do |name, default|
      __trait_define_writer_trait name, default, defaults, list
    end
    argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
    __trait_search_path.map{|ta| ta.__trait_instance_method_list['writers']}.flatten
#--}}}
  end
  %w( 
      instance_writer_traits
      instance_writer_trait
      writer_traits
      writer_trait
      wtraits
      wtrait
      w_traits
      w_trait
      has_writers
      has_writer
      has_w
    ).each{|meth| alias_method meth, '__trait_define_instance_writer_traits'}

  def __trait_define_instance_traits(*args, &block)
#--{{{
    writers = __trait_define_instance_writer_traits(*args, &block)
    readers = __trait_define_instance_reader_traits(*args, &block)
    [readers, writers]
#--}}}
  end
  %w( 
      instance_traits
      instance_trait
      traits
      trait
      has
    ).each{|meth| alias_method meth, '__trait_define_instance_traits'}

  def __trait_define_class_reader_traits(*args, &block)
#--{{{
    __trait_define_singleton_reader_traits(*args, &block)
#--}}}
  end
  %w( 
      class_reader_traits
      class_reader_trait
      class_rtraits
      class_rtrait
      class_r_traits
      class_r_trait
      class_has_readers
      class_has_reader
      class_has_r
      c_has_readers
      c_has_reader
      c_has_r
    ).each{|meth| alias_method meth, '__trait_define_class_reader_traits'}

  def __trait_define_class_writer_traits(*args, &block)
#--{{{
    __trait_define_singleton_writer_traits(*args, &block)
#--}}}
  end
  %w( 
      class_writer_traits
      class_writer_trait
      class_wtraits
      class_wtrait
      class_w_traits
      class_w_trait
      class_has_writers
      class_has_writer
      class_has_w
      c_has_writers
      c_has_writer
      c_has_w
    ).each{|meth| alias_method meth, '__trait_define_class_writer_traits'}

  def __trait_define_class_traits(*args, &block)
#--{{{
    __trait_define_singleton_traits(*args, &block)
#--}}}
  end
  %w( 
      class_traits
      class_trait
      class_has
      c_has
    ).each{|meth| alias_method meth, '__trait_define_class_traits'}

  def __trait_define_reader_trait name, default, defaults, list
#--{{{
      getter = "#{ name }"
      setter = "#{ name }="
      query = "#{ name }?"

      defaults[getter] = default if default
      list['readers'] << getter 

      unless instance_methods.include? getter
        code = __trait_gen_reader_code name, 'public'
        __trait_module_eval code
      end
      unless instance_methods.include? setter
        code = __trait_gen_writer_code name, 'private'
        __trait_module_eval code
      end
      unless instance_methods.include? query
        code = __trait_gen_query_code name, 'public'
        __trait_module_eval code
      end
#--}}}
  end

  def __trait_define_writer_trait name, default, defaults, list
#--{{{
      reader = "#{ name }"
      writer = "#{ name }="
      query = "#{ name }?"

      defaults[reader] = default if default
      list['writers'] << writer 

      unless instance_methods.include? reader
        code = __trait_gen_reader_code name, 'private'
        __trait_module_eval code
      end
      unless instance_methods.include? writer
        code = __trait_gen_writer_code name, 'public'
        __trait_module_eval code
      end
      unless instance_methods.include? query
        code = __trait_gen_query_code name, 'private'
        __trait_module_eval code
      end
#--}}}
  end

  def __trait_gen_reader_code name, access_protection = 'public' 
#--{{{
    s = __trait_singleton?
    klass = s ? 'self' : 'self.class'
    defaults = s ? '__trait_singleton_method_defaults' : '__trait_instance_method_defaults'
    search_ancestors = s ? 'true' : 'false'

    getter_meth = "#{ name }"
    setter_meth = "#{ name }="
    query_meth = "#{ name }?"
    ivar = "@#{ name }"
    getter = "'#{ name }'"
    setter = "'#{ name }='"

    reader_code = <<-code
      def #{ name }(*a, &b)
        unless a.empty?
          send('#{ name }=', *a, &b)
        else
          unless(defined?(@________#{ name }_set) and @________#{ name }_set)
            #{ klass }::__trait_search_path.each do |obj|
                defaults = obj.#{ defaults }
                if defaults.has_key? '#{ name }'
                  d = defaults['#{ name }']
                  if d.respond_to? '__trait_default'
                    d = instance_eval &d
                  end
                  return(send('#{ name }=', d))
                end
            end
          end
          case self
            when Class
              if defined? @#{ name }
                @#{ name }
              else
                __trait_search_path.each do |obj|
                  if self != obj and obj.respond_to? '#{ name }'
                    return(obj.send('#{ name }', *a,  &b))
                  end
                end
                return nil
              end
            else
              @#{ name }
          end
        end
      end
      #{ access_protection } '#{ name }'.intern
    code
    puts reader_code if $__TRAIT_DEBUG__
    reader_code
#--}}}
  end

  def __trait_gen_writer_code name, access_protection = 'public' 
#--{{{
    s = __trait_singleton?
    klass = s ? 'self' : 'self.class'
    hooks = s ? '__trait_singleton_method_hooks' : '__trait_instance_method_hooks'

    writer_code = <<-code
      def #{ name }=(head, *tail)
        value = tail.empty? ? head : [head] + tail
        #hooks = #{ klass }::#{ hooks }['#{ name }']
        hooks = nil
        #{ klass }::__trait_search_path.each do |obj|
          hooks = obj.#{ hooks }['#{ name }'] and break
        end
        pre, post, validate = hooks.values_at 'pre', 'post', 'validate'
        if pre
          __trait_evaluate value, &pre if pre
        end
        if validate
          valid = __trait_evaluate value, &validate
          raise ArgumentError, 
            "validation of #{ name }=(\#{ value.inspect }) failed!" unless valid
        end
        @#{ name } = value 
        @________#{ name }_set = true 
        if post
          __trait_evaluate value, &post
        end
        @#{ name }
      end
      #{ access_protection } '#{ name }='.intern
    code
#--}}}
  end

  def __trait_gen_query_code name, access_protection = 'public' 
#--{{{
    query_code = <<-code
      def #{ name }?
        send('#{ name }') ? true : false
      end
      # #{ access_protection } '#{ name }?'.intern
    code
    puts query_code if $__TRAIT_DEBUG__
    query_code
#--}}}
  end

  def __trait_gen_access_protection_code name, access_protection = nil 
#--{{{
    access_protection ||= 'public' 
    access_protection_code =
      case access_protection
        when %r/private/
          "private '#{ name }'.intern"
        when %r/protected/
          "protected '#{ name }'.intern"
        else
          "public '#{ name }'.intern"
      end
    puts access_protection_code if $__TRAIT_DEBUG__
    access_protection_code
#--}}}
  end
#--}}}
end
