require 'rbconfig'
require 'fileutils'

require 'facet/fileutils/safe_ln'
require 'facet/string/tabto'
require 'facet/module/basename'
require 'facet/module/attr_setter'

require 'facet/filelist' unless defined?( FileList )
require 'facet/openobject'

#  _____        _     ___                  ___ _
# |_   _|_ _ __| |__ | _ ) __ _ ___ ___   / __| |__ _ ______
#   | |/ _` (_-< / / | _ \/ _` (_-</ -_) | (__| / _` (_-<_-<
#   |_|\__,_/__/_\_\ |___/\__,_/__/\___|  \___|_\__,_/__/__/
#

# Base class for reap tasks.
#
# Here's a simple example:
#
#   class MyTask < Reap::Task
#
#     task_desc 'this is a custom reap task'
#
#     task_attr :mytask
#
#     def init
#       mytask.message ||= 'None Found!'
#     end
#
#     def run
#       puts mytask.message  #=> Hello!
#       puts master.default  #=> Yo!
#       puts mytask.default  #=> Yo!   (inherited from master)
#     end
#   end
#
# With the corresponding settings in the ProjectInfo file as:
#
#   default: Yo!
#
#   mytask:
#     message: Hello!
#

module Reap

  class Task

    #include ::Config
    include ::FileUtils

    RUBY = ::Config::CONFIG['ruby_install_name']

    class << self

      # When this class is inherited the new task is registered.

      def inherited( base )
        task_list[base.task_name] = base
      end

      def task_list
        @task_list ||= {}
      end

      # task dsl

      def section_required( val ) ; @section_required = val ; end
      def section_required?       ; @section_required ; end

      def task_name
        basename.downcase
      end

      def task_desc( text=nil, &block )
        return @task_desc = proc { text } if text
        return @task_desc = block if block_given?
        return @task_desc.call
      end

      def task_help( text=nil, &block )
        return @task_help = proc { text } if text
        return @task_help = block if block_given?
        return @task_help.call
      end

      def task_attr( name )
        define_method(name) { @task }
      end


      def verify?
        if section_required?
          return $PROJECT_INFO.info.key?(task_name)
        end
        true
      end

      def master
        @master ||= CascadingOpenObject.new( $PROJECT_INFO )
      end

      # properties not to be looked up in master
      # if they are not in regular task section

#       def task_only_properties ; @task_only_properties ||= [] ; end
#       def task_only_property( *names )
#         @task_only_properties ||= []
#         @task_only_properties |= names.collect { |n| n.to_s }
#       end

    end #<< class

    # instance methods

    def task_name ; self.class.task_name ; end
    def task_desc ; self.class.task_desc ; end
    def task_help ; self.class.task_help ; end

    def section_required? ; self.class.section_required? ; end

    #def master ; ::ProjectInfo.info ; end
    def master  ; self.class.master  ; end
    def section ; @section ; end
    def task    ; @task    ; end

    def initialize( *args )
      #@master = CascadingOpenObject.new( $PROJECT_INFO )
      @args = args
    end

    # Run task for each section entires given.

    def execute( section=nil )
      section = section || master[task_name]
      case section
      when Array
        section.each do |s|
          initiate( s )
        end
      else
        initiate( section )
      end
    end

    # Per section entry execution of task.

    def initiate( section )
      @section = CascadingOpenObject.new( section )

      task_properties = {}  # needed?
      #self.class.task_only_properties.each { |t| section[t] ||= nil }
      task_properties = CascadingOpenObject.new( section )
      task_properties.__parent__ = master
      @task = task_properties

      # deprecate init ?
      if respond_to?( :init )
        if method(:init).arity == 0
          init
        else
          init( *@args )
        end
      end

      if method(:run).arity == 0
        run
      else
        run( *@args )
      end
    end

    # interface

    #def init
    #  raise "not implemented for '#{task_name}' task"
    #end

    def run
      raise "no action defined for task #{task_name}"
    end

    # Task support methods

    def use_subsection( name )
      subsection = @section.__send__(name)
      if subsection
        subsection.__parent__ = @section
        @task = subsection
      end
    end

    def sh( arg )
      puts arg
      system arg unless $PRETEND
    end

    def ask( question, answers=nil )
      print "#{question}"
      print " [#{answers}] " if answers
      until inp = $stdin.gets[0,1] ; sleep 1 ; end ; puts
      inp
    end

    def tell( statement )
      puts statement
    end

    def provide_setup_rb
      return true if File.exists?( 'setup.rb')
      # copy from data dir to current directory (Won't work with Gem!)
      f = File.join( Config::CONFIG['datadir'], 'reap', 'setup_rb', 'setup.rb' )
      if File.exists?(f)
        File.cp( f, '.' )
        true
      else
        nil
      end
    end

  end #class Task

end #module Reap