require_relative 'base/cache'

module EacLauncher
  module Instances
    class Base < ::EacLauncher::Path
      include ::Eac::SimpleCache
      include ::EacRubyUtils::Console::Speaker
      include ::EacLauncher::Instances::Base::Cache

      attr_reader :parent

      def initialize(path, parent)
        super(path)
        @parent = parent
      end

      def stereotypes_uncached
        EacLauncher::Stereotype.stereotypes.select { |s| s.match?(self) }
      end

      def stereotype?(stereotype)
        stereotypes.include?(stereotype)
      end

      def children
        scan(self)
      end

      def to_parent_path
        return self unless @parent
        gsub(/\A#{Regexp.quote(@parent)}/, '')
      end

      def to_root_path
        gsub(/\A#{root}/, '')
      end

      def project?
        stereotypes.any?
      end

      def publish_run
        stereotypes.each do |s|
          next unless publish?(s)
          infov(to_root_path, "publishing #{s.stereotype_name_in_color}")
          s.publish_class.new(self).run
        end
      end

      def publish_check
        stereotypes.each do |s|
          next unless publish?(s)
          puts "#{to_root_path.to_s.cyan}|#{s.stereotype_name_in_color}|" \
            "#{s.publish_class.new(self).check}"
        end
      end

      def project_name
        File.basename(self)
      end

      def current_cache
        stereotypes.each do |s|
          return s.warp_class.new(self) if s.warp_class
        end
        raise ::EacLauncher::Instances::Error, "None stereotype of \"#{to_root_path}\" has " \
          "subclass \"CurrentCache\" (#{stereotypes.join(', ')})"
      end

      private

      def publish?(stereotype)
        return false unless stereotype.publish_class
        filter = ::EacLauncher::Context.current.publish_options[:stereotype]
        filter.blank? ? true : filter == stereotype.name.demodulize
      end

      def options_uncached
        ::EacLauncher::Context.current.settings.instance_settings(self)
      end

      def root_uncached
        return self unless @parent
        @parent.root
      end

      def scan(path)
        r = []
        scan_subdirectories(path) do |sp|
          c = self.class.new(sp, self)
          if c.stereotypes.any?
            r << c
          else
            r += scan(sp)
          end
        end
        r
      end

      def scan_subdirectories(path)
        Dir.entries(path).each do |basename|
          next if basename == '.' || basename == '..'
          sp = path.subpath(basename)
          next unless File.directory?(sp)
          yield(sp)
        end
      end
    end
  end
end