require_relative 'handler_accessors'

module Soaspec

  # Inherit this for a class describing how to implement a particular exchange.
  # Has basic methods common for methods defining RSpec tests in YAML
  class ExchangeHandler
    extend Soaspec::HandlerAccessors

    # Retrieve the name of the template file to be used in the API request
    attr_reader :template_name

    # Explicitly defined elements for which a path has been predefined
    def elements
      public_methods.select { |i| i[/__custom_path_.+/] }
    end

    # Set the default hash representing data to be used in making a request
    # This will set the @request_option instance variable too
    def default_hash=(hash)
      @request_option = :hash
      @default_hash = Soaspec.always_use_keys? ? hash.transform_keys_to_symbols : hash
    end

    # Set instance variable name
    # @param [String, Symbol] name Name used when describing API test
    # @param [Hash] options Parameters defining handler. Used in descendants
    def initialize(name = self.class.to_s, options = {})
      use
      @name = name
    end

    # Set Api handler used by Exchange class to this handler
    # @return [Self]
    def use
      Soaspec.api_handler = self
      self
    end

    # Sets api handler variable globally. This is used in 'Exchange' class
    # @return [String] Name set upon initialisation
    def to_s
      use
      @name.to_s
    end

    # Set the request option type and the template name
    # Erb is used to parse the template file, executing Ruby code in `<%= %>` blocks to work out the final request
    # @param [String] name Name of file inside 'template' folder excluding extension
    def template_name=(name)
      @request_option = :template
      @template_name = name
    end

    # Will be used in 'success_scenarios' shared examples.
    # Set though 'mandatory_elements' method
    # @return [Array] Array of symbols specifying element names
    def expected_mandatory_elements
      []
    end

    # Change this through 'mandatory_xpath_values' method to specify xpath results that must be present in the response
    # Will be used in 'success_scenarios' shared examples
    # @return [Hash] Hash of 'xpath' => 'expected value' pairs
    def expected_mandatory_xpath_values
      {}
    end

    # Change this through 'mandatory_json_values' method to specify json results that must be present in the response
    # Will be used in 'success_scenarios' shared examples
    # @return [Hash] Hash of 'json/path' => 'expected value' pairs
    def expected_mandatory_json_values
      {}
    end

    # @return [Boolean] Whether all xpaths will be done with XML that is converted to lower case
    def convert_to_lower?
      false
    end

    # Stores a value in a method that can be accessed by the provided name
    # @param [Symbol] name Name of method to use to access this value within handler
    # @param [String] value Value to store
    def store(name, value)
      define_singleton_method('__stored_val__' + name.to_s) do
        value
      end
    end

    # Set instance variable and remove it from Hash
    def set_remove_key(hash, key)
      return unless hash.key? key
      __send__("#{key}=", hash[key])
      hash.delete key
    end

  end
end