module Minke
  module Config
    ##
    # Reader reads a yaml based configuration and processes it into a Minke::Config::Config instance
    class Reader

      def initialize logger
        @logger = logger 
      end


      ##
      # read yaml config file and return Minke::Config::Config instance
      def read config_file
        b = binding

        config = Config.new
        file   = ERB.new(File.read(config_file)).result b
        file   = YAML.load(file)

        config.namespace        = file['namespace']
        config.application_name = file['application_name']
        config.generator_name   = file['generator_name']

        config.docker_registry = read_docker_registry file['docker_registry'] unless file['docker_registry'] == nil
        config.docker          = read_docker_section file['docker']           unless file['docker'] == nil

        config.fetch     = read_task_section file['fetch'],     config.docker unless file['fetch'] == nil
        config.build     = read_task_section file['build'],     config.docker unless file['build'] == nil
        config.test      = read_task_section file['test'],      config.docker unless file['test'] == nil
        config.run       = read_task_section file['run'],       config.docker unless file['run'] == nil
        config.cucumber  = read_task_section file['cucumber'],  config.docker unless file['cucumber'] == nil
        config.shell     = read_task_section file['shell'],     config.docker unless file['shell'] == nil
        config.provision = read_task_section file['provision'], config.docker unless file['provision'] == nil

        return config
      end

      def read_docker_registry section
        DockerRegistrySettings.new.tap do |d|
          d.url       = section['url'].is_a?(Hash) ? read_secure(section['url']) : section['url']
          d.user      = section['user'].is_a?(Hash) ? read_secure(section['user']) : section['user']
          d.password  = section['password'].is_a?(Hash) ? read_secure(section['password']) : section['password']
          d.email     = section['email'].is_a?(Hash) ? read_secure(section['email']) : section['email']
          d.namespace = section['namespace'].is_a?(Hash) ? read_secure(section['namespace']) : section['namespace']
        end
      end

      def read_docker_section section
        DockerSettings.new.tap do |d|
          d.build_image              = section['build_image']              unless section['build_image'] == nil
          d.build_docker_file        = section['build_docker_file']        unless section['build_docker_file'] == nil
          d.application_docker_file  = section['application_docker_file']  unless section['application_docker_file'] == nil
          d.application_compose_file = section['application_compose_file'] unless section['application_compose_file'] == nil
          d.working_directory        = section['working_directory']        unless section['working_directory'] == nil
        end
      end

      def read_task_section section, docker_config
        Task.new.tap do |t|
          t.consul_loader = read_consul_loader_section section['consul_loader']  unless section['consul_loader'] == nil
          t.health_check  = read_url section['health_check']                     unless section['health_check'] == nil
          t.docker        = read_docker_section section['docker']                unless section['docker'] == nil
          t.pre           = read_pre_post_section section['pre']                 unless section['pre'] == nil
          t.post          = read_pre_post_section section['post']                unless section['post'] == nil
          t.ports         = section['ports']                                     unless section['ports'] == nil
          t.terraform     = read_terraform_section section['terraform']          unless section['terraform'] == nil
        end
      end

      def read_pre_post_section section
        TaskRunSettings.new.tap do |tr|
          tr.tasks         = section['tasks']                  unless section['tasks'] == nil
          tr.copy          = read_copy_section section['copy'] unless section['copy'] == nil
        end
      end

      def read_copy_section section
        section.map do |s|
          Copy.new.tap do |c|
            c.from = s['from']
            c.to   = s['to']
          end
        end
      end

      def read_consul_loader_section section
        ConsulLoader.new.tap do |c|
          c.config_file = section['config_file']
          c.url         = read_url section['url']
        end
      end

      def read_terraform_section section
        TerraformSettings.new.tap do |t|
          t.config_dir = section['config_dir']
          t.environment = read_env_vars section['environment'] unless section['environment'] == nil
        end
      end

      def read_env_vars section
        env = EnvironmentSettings.new

        section.each do |e|
          e.each do |k,v|
            env[k]  = v.is_a?(Hash) ? read_secure(v) : v
          end
        end

        env
      end

      def read_url section
        URL.new.tap do |url|
          url.address  = section['address']
          url.port     = section['port']     != nil ? section['port'].to_s : '80'
          url.path     = section['path']     != nil ? section['path'] : ''
          url.protocol = section['protocol'] != nil ? section['protocol'] : 'http'
          url.type     = section['type']
        end
      end

      def read_secure hash
        key_path = ENV['SSL_KEY_PATH'].to_s == '' ? "#{ENV['HOME']}/.ssh" : ENV['SSL_KEY_PATH']
        unless Dir.exists? key_path
          @logger.error "Unable to find SSH keys to decrypt secrets, please set environment variable SSL_KEY_PATH or place the keys in ~/.ssh"
          return
        end

        fingerprint = hash['secure']['fingerprint']
        value = hash['secure']['value']

        locator = Minke::Encryption::KeyLocator.new key_path
        key_path = locator.locate_key fingerprint

        @logger.debug key_path

        if key_path.to_s.empty?
          @logger.error "Unable to find SSL key matching fingerprint if your SSL keys are not in ~/.ssh you can set the environment variable SSL_KEY_PATH to point to the correct directory.", :error
          return
        end

        encrypt = Minke::Encryption::Encryption.new key_path
        encrypt.decrypt_string value
      end

    end
  end
end
