module Ridley
  module CommandContext
    # Context class for generating an upgrade command for an Omnibus Chef installation on Windows based OSes
    class WindowsUpdateOmnibus < CommandContext::Windows
      template_file 'windows_update_omnibus'

      # @return [String]
      attr_reader :chef_version

      # @return [Boolean]
      attr_reader :prerelease

      # @return [String]
      attr_reader :direct_url

      def initialize(options = {})
        super(options)
        options = options.reverse_merge(chef_version: "latest", prerelease: false)
        @chef_version = options[:chef_version]
        @prerelease = options[:prerelease]
        @direct_url = options[:direct_url]
      end

      # @return [String]
      def update_dir
        "C:\\chef\\update"
      end

      # @return [String]
      def recipe_path
        "#{update_dir}\\default.rb"
      end

      # @return [String]
      def tmp_cookbook_path
        "#{update_dir}\\cookbooks\\upgrade_omnibus"
      end

      # @return [String]
      def tmp_recipes_path
        "#{tmp_cookbook_path}\\recipes"
      end

      # @return [String]
      def upgrade_solo_rb_path
        "#{update_dir}\\upgrade_solo.rb"
      end

      # @return [String]
      def chef_solo_command
        "chef-solo -c #{upgrade_solo_rb_path} -o upgrade_omnibus"
      end

      # @return [String]
      def chef_apply_command
        "chef-apply #{recipe_path}"
      end

      # Writes a recipe that uses remote_file to download the appropriate
      # Chef MSI file
      #
      # @return [String]
      def recipe_code
        code = <<-RECIPE_CODE
chef_version = '#{chef_version}'
prerelease = #{prerelease}

platform = node[:platform]
platform_version = if node[:product_type] == 1 # Not server
  case node[:platform_version]
  when /6\.1\./
    "7"
  when /6\.2\./
    "8"
  end
else # server
  case node[:platform_version]
  when /5\.2\.3/
    "2003r2"
  when /6\.0\./
    "2008"
  when /6\.1\./
    "2008r2"
  when /6\.2\./
    "2012"
  when /6\.3\./
    "2012r2"
  end
end

machine = node[:kernel][:machine]
nightlies = false

url = 'http://www.opscode.com/chef/download'
url_args = [ "p=\#{platform}", "pv=\#{platform_version}", "m=\#{machine}", "v=\#{chef_version}", "prerelease=\#{prerelease}", "nightlies=\#{nightlies}" ]

composed_url = "\#{url}?\#{url_args.join '&'}"

#{direct_url.nil? ? "full_url = composed_url" : "full_url = \"#{direct_url}\""}
request = Chef::REST::RESTRequest.new(:head, URI.parse(full_url), nil)
result = request.call

if result.kind_of?(Net::HTTPRedirection)
  full_url = result['location']
end

file_name = ::File.basename(full_url)
file_download_path = "C:\\\\chef\\\\update\\\\\#{file_name}"

remote_file file_download_path do
  source full_url
  backup false
  action :create_if_missing
end

file_extension = ::File.extname(file_name)

RECIPE_CODE
        escape_and_echo(code)
      end

      # Uses powershell to find a Chef installation and uninstalls it
      #
      # @return [String]
      def uninstall_chef
        win_uninstall_chef = <<-UNIN_PS
      $productName      = "Chef"
      $app = Get-WmiObject -Class Win32_Product | Where-Object {  $_.Name -match $productName  }
      If ($app) { $app.Uninstall() }
        UNIN_PS

        escape_and_echo(win_uninstall_chef)
      end

      private

      # escape WIN BATCH special chars and prefixes each line with an
      # echo
      def escape_and_echo(file_contents)
        file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
      end
    end
  end
end