require 'guard'
require 'guard/guard'

module Guard
  class CucumberJS < Guard

    autoload :Runner, 'guard/cucumber-js/runner'

    def initialize(watchers=[], opts={})
      super
      defaults = {
        :require => [],
        :tags => [],
        :all_after_pass => true,
        :all_on_start => true,
        :keep_failed => true,
        :feature_paths => ['features'],
        :run_all => {}
      }
      @options = defaults.merge(opts)
      @last_failed = false
      @failed_paths = []

      @runner = Runner.new(@options)
    end

    def start
      UI.info "Guard::CucumberJS is running, with cucumber.js #{@runner.cucumber_js_version}"
      run_all if run_all_on_start?
    end

    def run_all
      passed = @runner.run(@options[:feature_paths], @options[:run_all].merge(:message => 'Running all features'))

      unless @last_failed = !passed
        @failed_paths = []
      else
        throw :task_has_failed
      end
    end

    def reload
      @failed_paths = []
    end

    def run_on_change(paths)
      paths = paths_to_run(paths)

      if passwd = @runner.run(paths)
        remove_failed(paths)

        if @last_failed && run_all_after_pass?
          @last_failed = false
          run_all
        end
      else
        @last_failed = true
        add_failed(paths)
        throw :task_has_failed
      end
    end

    private

    def run_all_on_start?
      !!@options[:all_on_start]
    end

    def run_all_after_pass?
      !!@options[:all_after_pass]
    end

    def keep_failed?
      !!@options[:keep_failed]
    end

    def remove_failed(paths)
      @failed_paths -= paths if keep_failed?
    end

    def add_failed(paths)
      @failed_paths += paths if keep_failed?
      @failed_paths.uniq!
    end

    def paths_to_run(paths) 
      keep_failed? ? paths + @failed_paths : paths
    end

  end
end
