module ExpressTemplates
  module Components
    module Capabilities

      # Configurable components accept options which they can use to alter
      # their markup each time they are invoked within a template.
      #
      # They do not compile their markup fragments at load time as simpler
      # components do for efficiency.  Rather they compile their fragments
      # when they are themselves undergoing compilation.  This facilitates
      # access to arguments which were passed to the component at initialization.
      #
      # For example, if we have a Row component that is Configurable:
      #
      #     row(:main)
      #
      # might process to:
      #
      #     <div id="main" class="row" />
      #

      module Configurable
        def self.included(base)
          base.class_eval do
            extend ClassMethods
            include InstanceMethods

            # Stores arguments for later processing, eg., compile time
            def initialize(*args)
              @args = args.dup
              _process_args!(args)
              super(*args)
            end
          end
        end

        module ClassMethods

          protected

            # Override Templating._compile_fragment to delay compilation
            def _compile_fragment(block, options = {})
              if options.delete(:force_compile)
                super(block, options)
              else
                block
              end
            end

            def _lookup(name, options = {})
              super(name, options.merge(force_compile: true))
            end

        end

        module InstanceMethods

          def config
            @config ||= {}
          end

          alias :my :config

          def expand_locals
            {my: config}
          end

          # Override Templating#lookup to pass locals
          def lookup(fragment_name, options = {})
            super(fragment_name, options.merge(expand_locals))
          end


          private

            def _process_args!(args)
              if args.first.kind_of?(Symbol)
                config.merge!(id: args.shift)
              end
              while arg = args.shift
                if arg.kind_of?(Hash)
                  config.merge!(arg)
                end
              end
            end
        end
      end
    end
  end
end