namespace :handcuffs do

 task :migrate, [:phase] => :environment do |t,args|
   phase = setup(args, 'handcuffs:migrate')
   patch_migrator!(phase)
   run_task('db:migrate')
 end

 task :rollback, [:phase] => :environment do |t,args|
   phase = setup(args, 'handcuffs:rollback')
   patch_migrator!(phase)
   run_task('db:rollback')
 end

 def setup(args, task)
   phase = args.phase
   raise RequiresPhaseArgumentError.new(task) unless phase.present?
   raise HandcuffsNotConfiguredError.new unless Handcuffs.config
   phase = phase.to_sym
   unless Handcuffs.config.phases.include?(phase) || phase == :all
     raise HandcuffsUnknownPhaseError.new(phase, Handcuffs.config.phases)
   end
   phase
 end

 def patch_migrator!(phase)
   ActiveRecord::Migrator.prepend(PendingFilter)
   ActiveRecord::Migrator.extend(PhaseAccessor)
   ActiveRecord::Migrator.handcuffs_phase = phase
 end

 def run_task(name)
   Rake::Task.clear # necessary to avoid tasks being loaded several times in dev mode
   Rails.application.load_tasks 
   Rake::Task[name].reenable # in case you're going to invoke the same task second time.
   Rake::Task[name].invoke
 end

 module PendingFilter
   def runnable
     attempted_phase = self.class.handcuffs_phase
     if(@direction == :up)
       Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(super)
     else
       phase_migrations = Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(migrations)
       runnable = phase_migrations[start..finish]
       runnable.pop if target
       runnable.find_all { |m| ran?(m) }
     end
   end
end

 module PhaseAccessor
   attr_accessor :handcuffs_phase
 end

end