require 'rails/generators/active_record'

module ScaffoldPlus
  module Generators
    class HabtmGenerator < ActiveRecord::Generators::Base
      desc "Add many-to-many association with has_and_belongs_to_many"
      argument :name, type: :string,
               desc: "The first object that has_and_belongs_to_many OTHERs"
      argument :other, type: :string,
               desc: "The second object that has_and_belongs_to_many NAMEs"
      class_option :migration, type: :boolean, default: true,
               desc: 'Create a migration for the join table'
      class_option :permit, type: :boolean, default: true,
               desc: 'Allow mass assignment for added attributes in NAME'
      class_option :before, type: :array,
               desc: 'Add a line before generated text in models'
      class_option :after, type: :array,
               desc: 'Add a line after generated text in models'
      source_root File.expand_path('../templates', __FILE__)
      
      def add_migration
        return unless options.migration?
        migration_template "habtm_migration.rb", "db/migrate/#{habtm_migration_name}.rb"
      end
      
      def add_to_models
        inject_into_class "app/models/#{name}.rb", class_name do
          text = before_array.include?(name) ? "\n" : ""
          text << "  has_and_belongs_to_many :#{other.pluralize}\n"
          text << "\n" if after_array.include?(name)
          text
        end
        inject_into_class "app/models/#{other}.rb", other.camelize do
          text = before_array.include?(other) ? "\n" : ""
          text << "  has_and_belongs_to_many :#{table_name}\n"
          text << "\n" if after_array.include?(other)
          text
        end
      end
      
      def add_to_permit
        return unless options.permit?
        text = "{ :#{other}_ids => [] }"
        file = "app/controllers/#{table_name}_controller.rb"
        gsub_file file, /(permit\(.*)\)/, "\\1, #{text})"
        # Special case: no previous permit
        gsub_file file, /^(\s*params)\[:#{name}\]$/, "\\1.require(:#{name}).permit(#{text})"
      end
      
      protected
      
      def before_array
        options['before'] || []
      end
      
      def after_array
        options['after'] || []
      end
      
      def sorted_sg
        [name, other].sort
      end
      
      def sorted_pl
        [table_name, other.pluralize].sort
      end
      
      def habtm_migration_name
        "create_#{sorted_pl.first}_and_#{sorted_pl.second}"
      end
      
      def habtm_table_name
        "#{sorted_pl.first}_#{sorted_pl.second}"
      end
    end
  end
end