class Associator
  def initialize(target, context={})
    @target = target
    @legacy = context.delete(:legacy)
    if context.key?(:namespace)
      @namespace = context.delete(:namespace)
      @prefix = @namespace.underscore.tr('/', '_')
    end
    context[:primary_key] = context[:foreign_key] = context.delete(:keys) if context.key?(:keys)
    @context = context
  end

  def has_many(association, options={})
    has_options(association, options) { |a, o| @target.send :has_many, a, o }
  end

  def has_one(association, options={})
    has_options(association, options) { |a, o| @target.send :has_one, a, o }
  end

  def belongs_to(association, options={})
    belongs_options(association, options) { |a, o| @target.send :belongs_to, a, o }
  end

  private
    def has_options(association, options)
      context = @context
      if @legacy
        context[:inverse_of] = @target.name.underscore.tr('/', '_')
        context[:primary_key] = "#{@target.name}ID"
        context[:foreign_key] = context[:primary_key]
      end
      options = context.merge options
      options[:primary_key] = options[:foreign_key] = options.delete(:keys) if options.key?(:keys)
      unless @namespace.nil?
        unless options.key?(:class_name)
          options[:class_name] = "#{@namespace}::#{association.to_s.singularize.classify}"
        end
        if options.key?(:through)
          options[:through] = "#{@prefix}_#{options[:through]}"
          options[:source] = association unless options.key?(:source)
        end
        association = "#{@prefix}_#{association}".to_sym
      end
      yield(association, options)
    end

    def belongs_options(association, options)
      context = @context
      if @legacy
        context[:inverse_of] = @target.name.tableize.tr('/', '_')
        context[:primary_key] = "#{association.to_s.singularize.classify}ID"
        context[:foreign_key] = context[:primary_key]
      end
      options = context.merge(options)
      options[:primary_key] = options[:foreign_key] = options.delete(:keys) if options.key?(:keys)
      yield(association, options)
    end
end
