# encoding: utf-8
module Appium::Android
=begin
name, names, text, text should match substring and case insensitive.

In Android //* is used to find partial case insensitive text matches.
//* is not currently implemented in iOS.

find_element :name by default uses a partial case insensitive match.
On iOS the default is an exact name match.

```javascript
// iOS version
// https://github.com/appium/ruby_lib/blob/37bb4e90b29e5adb4438b287b6387a504c94b5c4/lib/appium_lib/element/ios/generic.rb#L23
var search = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'";
var a = w.secureTextFields().firstWithPredicate(search);
if ( isNil(a) ) {
  a = w.textFields().firstWithPredicate(search);
  if ( isNil(a) ) {
    a = w.buttons().firstWithPredicate(search);
    if ( isNil(a) ) {
      a = w.elements().firstWithPredicate(search);
    }
  }
}
```

Android considers both a textfield and a secure textfield to be "EditText".
Name (the content desc) is searched first and then we search for value (text).
There's no label in Android.

Android buttons have different class names (android.widget.Button, android.widget.ImageButton)
so we consider the element a button if the class name contains the word button.

After looking for textfields and buttons, then we search all elements. Find will return
the first element that matches.
=end

  # Find the value contained in content description or text. Search elements
  # in this order: EditText, Button, ImageButton
  #
  # @param val [String] the value to search for
  # @return [Element]
  def find val
    # s.className('android.widget.EditText').descriptionContains(value);
    args = [ [4, 'android.widget.EditText'], [7, val] ],
    # s.className('android.widget.EditText').textContains(value);
           [ [4, 'android.widget.EditText'], [3, val] ],

           # s.className('android.widget.Button').descriptionContains(value);
           [ [4, 'android.widget.Button'], [7, val] ],
           # s.className('android.widget.Button').textContains(value);
           [ [4, 'android.widget.Button'], [3, val] ],

           # s.className('android.widget.ImageButton').descriptionContains(value);
           [ [4, 'android.widget.ImageButton'], [7, val] ],
           # s.className('android.widget.ImageButton').textContains(value);
           [ [4, 'android.widget.ImageButton'], [3, val] ],

           # s.descriptionContains(value);
           [ [7, val] ],
           # s.textContains(value);
           [ [3, val] ]
    mobile :find, args
  end

  # Return the first element matching text.
  # @param text [String] the text to search for
  # @return [Element] the first matching element
  def text text
    # Return the first element matching selector.
    # s.textContains(value)
    mobile :find, [ [ [3, text] ] ]
  end

  # Return all elements matching text.
  # @param text [String] the text to search for
  # @return [Array<Element>] all matching elements
  def texts text
    @driver.find_elements :xpath, "//*[contains(@text, '#{text}')]"
  end

  # Return the first element matching name.
  # on Android name is content description
  # on iOS name is the accessibility label or the text.
  # @param name [String] the name to search for
  # @return [Element] the first matching element
  def name name
    # work around https://github.com/appium/appium/issues/543
    # @driver.find_element :name, name
    mobile :find, [ [ [7, name] ] ]
  end

  # Return the first element exactly matching name.
  # on Android name is content description
  # on iOS name is the accessibility label or the text.
  # @param name [String] the name to search for
  # @return [Element] the first matching element
  def name_exact name
    # exact description
    result = mobile :find, [ [ [5, name] ] ]

    return result if result.kind_of? Selenium::WebDriver::Element

    if result.length > 0
      result.first
    else
      Appium::Common.raise_no_element_error
    end
  end

  # Return all elements matching name.
  # on Android name is content description
  # on iOS name is the accessibility label or the text.
  # @param name [String] the name to search for
  # @return [Array<Element>] all matching elements
  def names name=''
    if name.nil? || name.empty?
      args = 'all', [ [7, ''], [100] ]
      mobile :find, args
    else
      args = 'all',
          [ [7, name] ]
      mobile :find, args
    end
  end

  # Scroll to an element containing target text or description.
  # @param text [String] the text to search for in the text value and content description
  # @return [Element] the element scrolled to
  def scroll_to text
    args = 'scroll',
        # textContains(text)
        [ [3, text] ],
        # descriptionContains(text)
        [ [7, text] ]

    mobile :find, args
  end

  # Scroll to an element with the exact target text or description.
  # @param text [String] the text to search for in the text value and content description
  # @return [Element] the element scrolled to
  def scroll_to_exact text
    args = 'scroll',
        # text(text)
        [ [1, text] ],
        # description(text)
        [ [5, text] ]

    mobile :find, args
  end
end # module Appium::Android