class Selenium::WebDriver::Support::Select

def deselect_all

def deselect_all
  raise Error::UnsupportedOperationError, 'you may only deselect all options of a multi-select' unless multiple?
  options.each { |e| deselect_option e }
end

def deselect_by(how, what)

def deselect_by(how, what)
  case how
  when :text
    deselect_by_text what
  when :value
    deselect_by_value what
  when :index
    deselect_by_index what
  else
    raise ArgumentError, "can't deselect options by #{how.inspect}"
  end
end

def deselect_by_index(index)

def deselect_by_index(index)
  raise Error::UnsupportedOperationError, 'you may only deselect option of a multi-select' unless multiple?
  opts = find_by_index index
  return deselect_option(opts.first) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate option with index: #{index}"
end

def deselect_by_text(text)

def deselect_by_text(text)
  raise Error::UnsupportedOperationError, 'you may only deselect option of a multi-select' unless multiple?
  opts = find_by_text text
  return deselect_options(opts) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
end

def deselect_by_value(value)

def deselect_by_value(value)
  raise Error::UnsupportedOperationError, 'you may only deselect option of a multi-select' unless multiple?
  opts = find_by_value value
  return deselect_options(opts) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
end

def deselect_option(option)

def deselect_option(option)
  option.click if option.selected?
end

def deselect_options(opts)

def deselect_options(opts)
  if multiple?
    opts.each { |o| deselect_option o }
  else
    deselect_option opts.first
  end
end

def find_by_index(index)

def find_by_index(index)
  options.select { |option| option.property(:index) == index }
end

def find_by_text(text)

def find_by_text(text)
  xpath = ".//option[normalize-space(.) = #{Escaper.escape text}]"
  opts = @element.find_elements(xpath: xpath)
  return opts unless opts.empty? && /\s+/.match?(text)
  longest_word = text.split(/\s+/).max_by(&:length)
  if longest_word.empty?
    candidates = options
  else
    xpath = ".//option[contains(., #{Escaper.escape longest_word})]"
    candidates = @element.find_elements(xpath: xpath)
  end
  return Array(candidates.find { |option| text == option.text }) unless multiple?
  candidates.select { |option| text == option.text }
end

def find_by_value(value)

def find_by_value(value)
  @element.find_elements(xpath: ".//option[@value = #{Escaper.escape value}]")
end

def first_selected_option

def first_selected_option
  option = options.find(&:selected?)
  return option if option
  raise Error::NoSuchElementError, 'no options are selected'
end

def initialize(element)

def initialize(element)
  tag_name = element.tag_name
  raise ArgumentError, "unexpected tag name #{tag_name.inspect}" unless tag_name.casecmp('select').zero?
  @element = element
  @multi = ![nil, 'false'].include?(element.dom_attribute(:multiple))
end

def multiple?

def multiple?
  @multi
end

def options

def options
  @element.find_elements tag_name: 'option'
end

def select_all

def select_all
  raise Error::UnsupportedOperationError, 'you may only select all options of a multi-select' unless multiple?
  options.each { |e| select_option e }
end

def select_by(how, what)

def select_by(how, what)
  case how
  when :text
    select_by_text what
  when :index
    select_by_index what
  when :value
    select_by_value what
  else
    raise ArgumentError, "can't select options by #{how.inspect}"
  end
end

def select_by_index(index)

def select_by_index(index)
  opts = find_by_index index
  return select_option(opts.first) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate element with index: #{index.inspect}"
end

def select_by_text(text)

def select_by_text(text)
  opts = find_by_text text
  return select_options(opts) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
end

def select_by_value(value)

def select_by_value(value)
  opts = find_by_value value
  return select_options(opts) unless opts.empty?
  raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
end

def select_option(option)

def select_option(option)
  raise Error::UnsupportedOperationError, 'You may not select a disabled option' unless option.enabled?
  option.click unless option.selected?
end

def select_options(opts)

def select_options(opts)
  if multiple?
    opts.each { |o| select_option o }
  else
    select_option opts.first
  end
end

def selected_options

def selected_options
  options.select(&:selected?)
end