
module HammerCLI

  module Subcommand

    class LazyDefinition < Clamp::Subcommand::Definition

      def initialize(names, description, subcommand_class_name, path)
        @names = Array(names)
        @description = description
        @subcommand_class_name = subcommand_class_name
        @path = path
        @loaded = false
      end

      def loaded?
        @loaded
      end

      def subcommand_class
        if !@loaded
          require @path
          @loaded = true
          @constantized_class = @subcommand_class_name.constantize
        end
        @constantized_class
      end

    end

    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods
      def remove_subcommand(name)
        self.recognised_subcommands.delete_if do |sc|
          if sc.is_called?(name)
            logger.info "subcommand #{name} (#{sc.subcommand_class}) was removed."
            true
          else
            false
          end
        end
      end

      def subcommand!(name, description, subcommand_class = self, &block)
        remove_subcommand(name)
        subcommand(name, description, subcommand_class, &block)
        logger.info "subcommand #{name} (#{subcommand_class}) was created."
      end

      def subcommand(name, description, subcommand_class = self, &block)
        existing = find_subcommand(name)
        if existing
          raise HammerCLI::CommandConflict, _("can't replace subcommand %<name>s (%<existing_class>s) with %<name>s (%<new_class>s)") % {
            :name => name,
            :existing_class => existing.subcommand_class,
            :new_class => subcommand_class
          }
        end
        super
      end

      def lazy_subcommand(name, description, subcommand_class, path)
        # call original subcommand to ensure command's parameters are set correctly
        # (hammer command SUBCOMMAND [ARGS] ...)
        subcommand(name, description, Class)
        # replace last subcommand definition with correct lazy-loaded one
        recognised_subcommands[-1] = LazyDefinition.new(name, description, subcommand_class, path)
      end

      def lazy_subcommand!(name, description, subcommand_class, path)
        remove_subcommand(name)
        self.lazy_subcommand(name, description, subcommand_class, path)
        logger.info "subcommand #{name} (#{subcommand_class}) was created."
      end

    end

  end
end
