/*
 * Copyright 2018 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.gnd.ui.common;

import android.net.Uri;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.databinding.BindingAdapter;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import com.google.android.gms.common.SignInButton;
import com.google.android.gnd.R;
import com.google.android.gnd.model.form.Field;
import com.google.android.gnd.model.observation.Response;
import com.google.android.gnd.ui.editobservation.MultipleChoiceFieldLayout;
import com.google.android.material.textfield.TextInputEditText;
import com.squareup.picasso.Picasso;
import java8.util.function.Consumer;

/**
 * Container for adapter methods defining custom data binding behavior. This class cannot be made
 * injectable, since binding adapters must be static.
 */
public class BindingAdapters {

  @BindingAdapter("android:text")
  public static void bindText(TextInputEditText view, Response response) {
    ViewDataBinding binding = findBinding(view);
    Field field = getField(binding);
    if (field == null) {
      // Binding update before attached to field.
      return;
    }
    String newText = response == null ? "" : response.getDetailsText(field);
    if (!view.getText().toString().equals(newText)) {
      view.setText(newText);
    }
  }

  private static ViewDataBinding findBinding(View view) {
    for (View v = view; v.getParent() instanceof View; v = (View) v.getParent()) {
      ViewDataBinding binding = DataBindingUtil.getBinding(v);
      if (binding != null) {
        return binding;
      }
    }
    return null;
  }

  private static Field getField(ViewDataBinding binding) {
    if (binding == null) {
      return null;
    } else {
      throw new IllegalArgumentException("Unknown binding type: " + binding.getClass());
    }
  }

  @BindingAdapter("onClick")
  public static void bindGoogleSignOnButtonClick(
      SignInButton button, View.OnClickListener onClickCallback) {
    button.setOnClickListener(onClickCallback);
  }

  @BindingAdapter("onTextChanged")
  public static void bindTextWatcher(TextInputEditText editText, Consumer onTextChanged) {
    editText.addTextChangedListener(
        new TextWatcher() {
          @Override
          public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            // No-op.
          }

          @Override
          public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            onTextChanged.accept(charSequence.toString());
          }

          @Override
          public void afterTextChanged(Editable editable) {
            // No-op.
          }
        });
  }

  @BindingAdapter("errorText")
  public static void bindError(TextInputEditText view, @Nullable String newErrorText) {
    if (view.getError() == null) {
      if (newErrorText != null) {
        view.setError(newErrorText);
      }
    } else if (!view.getError().equals(newErrorText)) {
      view.setError(newErrorText);
    }
  }

  @BindingAdapter("onFocusChange")
  public static void setOnFocusChangeListener(
      View view, final View.OnFocusChangeListener listener) {
    view.setOnFocusChangeListener(listener);
  }

  @BindingAdapter("onShowDialog")
  public static void setOnShowDialogListener(MultipleChoiceFieldLayout view, Runnable listener) {
    view.setOnShowDialogListener(listener);
  }

  @BindingAdapter("imageUri")
  public static void bindUri(ImageView view, Uri uri) {
    Picasso.get().load(uri).placeholder(R.drawable.ic_photo_grey_600_24dp).into(view);
  }
}

@@ -798,351 +798,118 @@
 idx.
-annotation.Nullable;%0Aimport androidx.databinding.BindingAdapter;%0Aimport androidx.databinding.DataBindingUtil;%0Aimport androidx.databinding.ViewDataBinding;%0Aimport com.google.android.gms.common.SignInButton;%0Aimport com.google.android.gnd.R;%0Aimport com.google.android.gnd.model.form.Field;%0Aimport com.google.android.gnd.model.observation.Response
+databinding.BindingAdapter;%0Aimport com.google.android.gms.common.SignInButton;%0Aimport com.google.android.gnd.R
 ;%0Aim
@@ -1317,980 +1317,8 @@
  %7B%0A%0A
-  @BindingAdapter(%22android:text%22)%0A  public static void bindText(TextInputEditText view, Response response) %7B%0A    ViewDataBinding binding = findBinding(view);%0A    Field field = getField(binding);%0A    if (field == null) %7B%0A      // Binding update before attached to field.%0A      return;%0A    %7D%0A    String newText = response == null ? %22%22 : response.getDetailsText(field);%0A    if (!view.getText().toString().equals(newText)) %7B%0A      view.setText(newText);%0A    %7D%0A  %7D%0A%0A  private static ViewDataBinding findBinding(View view) %7B%0A    for (View v = view; v.getParent() instanceof View; v = (View) v.getParent()) %7B%0A      ViewDataBinding binding = DataBindingUtil.getBinding(v);%0A      if (binding != null) %7B%0A        return binding;%0A      %7D%0A    %7D%0A    return null;%0A  %7D%0A%0A  private static Field getField(ViewDataBinding binding) %7B%0A    if (binding == null) %7B%0A      return null;%0A    %7D else %7B%0A      throw new IllegalArgumentException(%22Unknown binding type: %22 + binding.getClass());%0A    %7D%0A  %7D%0A%0A
   @B
@@ -2165,343 +2165,8 @@
  %7D%0A%0A
-  @BindingAdapter(%22errorText%22)%0A  public static void bindError(TextInputEditText view, @Nullable String newErrorText) %7B%0A    if (view.getError() == null) %7B%0A      if (newErrorText != null) %7B%0A        view.setError(newErrorText);%0A      %7D%0A    %7D else if (!view.getError().equals(newErrorText)) %7B%0A      view.setError(newErrorText);%0A    %7D%0A  %7D%0A%0A
   @B

Remove unused binding adapters