/*
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.litho.testing.viewtree;

import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.facebook.litho.ComponentHost;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import java.util.List;
import javax.annotation.Nullable;

/**
 * Function objects used for extracting specific information out of Android classes
 */
final class ViewExtractors {

  private ViewExtractors() {}

  public static final Function<View, String> GET_TEXT_FUNCTION = new Function<View, String>() {
    @Override
    public String apply(@Nullable View input) {
      CharSequence text = null;
      if (input instanceof ComponentHost) {
        List<CharSequence> strings = ((ComponentHost) input).getTextContent().getTextItems();
        if (!strings.isEmpty()) {
          text = Joiner.on("\", and \"").join(strings);
        }
      } else if (input instanceof TextView) {
        text = ((TextView) input).getText();
      }
      if (text == null) {
        return String.format(
            "No text found, view is %s",
            getVisibilityString(input.getVisibility()));
      }

      return String.format(
          "Found text: \"%s\", view is %s",
          Strings.nullToEmpty(text.toString()),
          getVisibilityString(input.getVisibility()));
    }
  };

  public static final Function<View, String> GET_DRAWABLE_FUNCTION = new Function<View, String>() {
    @Override
    public String apply(@Nullable View input) {
      if (!(input instanceof ImageView)) {
        return "No drawable found";
      }
      return String.format(
          "Found drawable: \"%s\", view is %s",
          getDrawableString((ImageView) input),
          getVisibilityString(input.getVisibility()));
    }
  };

  public static Function<View, String> GET_CONTENT_DESCRIPTION_FUNCTION
      = new Function<View, String>() {
    @Override
    public String apply(@Nullable View input) {
      if (input == null) {
        return "Provided view was null";
      }
      if (input.getContentDescription() == null) {
        return String.format(
            "No content description found, view is %s",
            getVisibilityString(input.getVisibility()));
      }
      return String.format(
          "Found content description: \"%s\", view is %s",
          input.getContentDescription(),
          getVisibilityString(input.getVisibility()));
    }
  };

  /**
   * Generates a function that extracts information about view tags from the given view.
   * @param key key that identifies the tag
   * @return function that extracts information about view tags
   */
  public static Function<View, String> generateGetViewTagFunction(final int key) {
    return new Function<View, String>() {
      @Override
      public String apply(View input) {
        if (input.getTag(key) == null) {
          return String.format(
              "No view tag found, view is %s",
              getVisibilityString(input.getVisibility()));
        }

        return String.format(
            "Found view tag: \"%s\", view is %s",
            input.getTag(key),
            getVisibilityString(input.getVisibility()));
      }
    };
  }

  /** A function that inputs a view and outputs the view's id and visibility. */
  public static Function<View, String> GET_VIEW_ID_FUNCTION = new Function<View, String>() {
    @Override
    public String apply(View input) {
      int id = input.getId();
      return String.format(
          "View with id \"%s=%d\" is %s.",
          ViewTreeUtil.getResourceName(id),
          id,
          getVisibilityString(input.getVisibility()));
    }
  };

  private static String getDrawableString(ImageView input) {
    Drawable drawable = input.getDrawable();
    return String.valueOf(drawable);
  }

  private static String getVisibilityString(int visibility) {
    return visibility == View.VISIBLE ? "visible" : "not visible";
  }
}

@@ -391,16 +391,47 @@
 awable;%0A
+import android.text.TextUtils;%0A
 import a
@@ -444,24 +444,24 @@
 .view.View;%0A
-
 import andro
@@ -671,16 +671,44 @@
 trings;%0A
+import java.util.ArrayList;%0A
 import j
@@ -1847,32 +1847,38 @@
 WABLE_FUNCTION =
+%0A     
  new Function%3CVi
@@ -1885,32 +1885,36 @@
 ew, String%3E() %7B%0A
+    
     @Override%0A  
@@ -1907,32 +1907,36 @@
   @Override%0A    
+   
+ 
 public String ap
@@ -1969,21 +1969,23 @@
 %7B%0A      
+    
 if 
-(!
 (input i
@@ -2004,20 +2004,23 @@
 ageView)
-)
  %7B%0A
+    
         
@@ -2030,222 +2030,893 @@
 urn 
-%22No drawable found%22;
+String.format(%0A                %22Found drawable: %5C%22%25s%5C%22, view is %25s%22,
 %0A      
-%7D%0A
+  
       
-return String.format(%0A          %22Found drawable: %5C%22%25s%5C%22, view is %25s%22,%0A          getDrawableString((ImageView) input),%0A          getVisibilityString(input.getVisibility()));%0A    %7D%0A
+  String.valueOf(((ImageView) input).getDrawable()),%0A                getVisibilityString(input.getVisibility()));%0A          %7D else if (input instanceof ComponentHost) %7B%0A            ComponentHost host = (ComponentHost) input;%0A            List%3CString%3E drawables = new ArrayList%3C%3E();%0A            for (Drawable d : host.getDrawables()) %7B%0A              drawables.add(String.valueOf(d));%0A            %7D%0A            for (Drawable d : host.getImageContent().getImageItems()) %7B%0A              drawables.add(String.valueOf(d));%0A            %7D%0A            return String.format(%0A                %22Found drawables: %5C%22%25s%5C%22, view is %25s%22,%0A                TextUtils.join(%22%5C%22, %5C%22%22, drawables), getVisibilityString(input.getVisibility()));%0A          %7D else %7B%0A            return %22No drawable found%22;%0A          %7D%0A        %7D%0A    
   %7D;
@@ -4781,162 +4781,14 @@
   %7D%0A
+
   %7D;%0A%0A
-  private static String getDrawableString(ImageView input) %7B%0A    Drawable drawable = input.getDrawable();%0A    return String.valueOf(drawable);%0A  %7D%0A%0A
   pr

Improve ViewExtractors failure message for ComponentHost