# modified version of parseconfig rubygem module
# 
# Author::      BJ Dierkes <derks@bjdierkes.com> 
# Copyright::   Copyright (c) 2006,2012 BJ Dierkes
# License::     MIT 
# URL::         https://github.com/derks/ruby-parseconfig
# 

# This class was written to simplify the parsing of configuration
# files in the format of "param = value".  Please review the
# demo files included with this package.
#
# For further information please refer to the './doc' directory
# as well as the ChangeLog and README files included.
#

# Note: A group is a set of parameters defined for a subpart of a
# config file

module RHC
  module Vendor
    class ParseConfig

      Version = '1.0.2'

      attr_accessor :config_file, :params, :groups

      # Initialize the class with the path to the 'config_file'
      # The class objects are dynamically generated by the
      # name of the 'param' in the config file.  Therefore, if
      # the config file is 'param = value' then the itializer
      # will eval "@param = value"
      #
      def initialize(config_file=nil)
        @config_file = config_file
        @params = {}
        @groups = []

        if(self.config_file)
          self.validate_config()
          self.import_config()
        end
      end

      # Validate the config file, and contents
      def validate_config()
        if !File.readable?(self.config_file)
          raise Errno::EACCES, "#{self.config_file} is not readable"
        end

        # FIX ME: need to validate contents/structure?
      end

      # Import data from the config to our config object.
      def import_config()
        # The config is top down.. anything after a [group] gets added as part
        # of that group until a new [group] is found.
        group = nil
        File.open(self.config_file) { |f| f.each do |line|
          line.strip!
          unless (/^\#/.match(line))
            if(/\s*=\s*/.match(line))
              param, value = line.split(/\s*=\s*/, 2)
              var_name = "#{param}".chomp.strip
              value = value.chomp.strip
              new_value = ''
              if (value)
                if value =~ /^['"](.*)['"]$/
                  new_value = $1
                else
                  new_value = value
                end
              else
                new_value = ''
              end

              if group
                self.add_to_group(group, var_name, new_value)
              else
                self.add(var_name, new_value)
              end

            elsif(/^\[(.+)\]$/.match(line).to_a != [])
              group = /^\[(.+)\]$/.match(line).to_a[1]
              self.add(group, {})

            end
          end
        end }
      end

      # This method will provide the value held by the object "@param"
      # where "@param" is actually the name of the param in the config 
      # file.  
      #
      # DEPRECATED - will be removed in future versions
      #
      def get_value(param)
        puts "ParseConfig Deprecation Warning: get_value() is deprecated. Use " + \
             "config['param'] or config['group']['param'] instead."
        return self.params[param]
      end

      # This method is a shortcut to accessing the @params variable
      def [](param)
        return self.params[param]
      end

      # This method returns all parameters/groups defined in a config file.
      def get_params()
        return self.params.keys
      end

      # List available sub-groups of the config.
      def get_groups()
        return self.groups
      end

      # This method adds an element to the config object (not the config file)
      # By adding a Hash, you create a new group
      def add(param_name, value)
        if value.class == Hash
          if self.params.has_key?(param_name)
            if self.params[param_name].class == Hash
              self.params[param_name].merge!(value)
            elsif self.params.has_key?(param_name)
              if self.params[param_name].class != value.class
                raise ArgumentError, "#{param_name} already exists, and is of different type!"
              end
            end
          else
            self.params[param_name] = value
          end
          if ! self.groups.include?(param_name)
            self.groups.push(param_name)
          end
        else
          self.params[param_name] = value
        end
      end

      # Add parameters to a group. Note that parameters with the same name
      # could be placed in different groups
      def add_to_group(group, param_name, value)
        if ! self.groups.include?(group)
          self.add(group, {})
        end
        self.params[group][param_name] = value
      end

      # Writes out the config file to output_stream
      def write(output_stream=STDOUT)
        self.params.each do |name,value| 
          if value.class.to_s != 'Hash'
            if value.scan(/\w+/).length > 1
              output_stream.puts "#{name} = \"#{value}\""
            else
              output_stream.puts "#{name} = #{value}"
            end
          end
        end
        output_stream.puts "\n"

        self.groups.each do |group|
          output_stream.puts "[#{group}]"
          self.params[group].each do |param, value| 
            if value.scan(/\w+/).length > 1
              output_stream.puts "#{param} = \"#{value}\""
            else
              output_stream.puts "#{param} = #{value}"
            end
          end
          output_stream.puts "\n"
        end
      end
    end
  end
end
