/*
 * Copyright 2014-present Facebook, Inc.
 *
 * 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
 *
 *   http://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.facebook.litho.widget;

import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import com.facebook.litho.ThreadUtils;

/**
 * An controller that can be passed as {@link com.facebook.litho.annotations.Prop} to a Recycler
 * component to trigger events from outside the component hierarchy.
 */
public class RecyclerEventsController {

  public interface OnRecyclerUpdateListener {

    void onUpdate(@Nullable RecyclerView recyclerView);
  }

  @Nullable private SectionsRecyclerView mSectionsRecyclerView;

  @Nullable private OnRecyclerUpdateListener mOnRecyclerUpdateListener;

  private final Runnable mClearRefreshRunnable =
      new Runnable() {
        @Override
        public void run() {
          if (mSectionsRecyclerView != null && mSectionsRecyclerView.isRefreshing()) {
            mSectionsRecyclerView.setRefreshing(false);
          }
        }
      };

  /**
   * Send the Recycler a request to scroll the content to the first item in the binder.
   *
   * @param animated if animated is set to true the scroll will happen with an animation.
   */
  public void requestScrollToTop(boolean animated) {
    requestScrollToPosition(0, animated);
  }

  /**
   * Send the Recycler a request to scroll the content to a specific item in the binder.
   *
   * @param animated if animated is set to true the scroll will happen with an animation.
   */
  public void requestScrollToPosition(final int position, final boolean animated) {
    if (mSectionsRecyclerView == null) {
      return;
    }

    if (animated) {
      mSectionsRecyclerView.getRecyclerView().smoothScrollToPosition(position);
      return;
    }

    mSectionsRecyclerView.getRecyclerView().scrollToPosition(position);
  }

  public void clearRefreshing() {
    if (mSectionsRecyclerView == null || !mSectionsRecyclerView.isRefreshing()) {
      return;
    }

    if (ThreadUtils.isMainThread()) {
      mSectionsRecyclerView.setRefreshing(false);
      return;
    }

    mSectionsRecyclerView.removeCallbacks(mClearRefreshRunnable);
    mSectionsRecyclerView.post(mClearRefreshRunnable);
  }

  public void showRefreshing() {
    if (mSectionsRecyclerView == null || mSectionsRecyclerView.isRefreshing()) {
      return;
    }
    ThreadUtils.assertMainThread();
    mSectionsRecyclerView.setRefreshing(true);
  }

  void setSectionsRecyclerView(@Nullable SectionsRecyclerView sectionsRecyclerView) {
    mSectionsRecyclerView = sectionsRecyclerView;

    if (mOnRecyclerUpdateListener != null) {
      mOnRecyclerUpdateListener.onUpdate(
          sectionsRecyclerView == null ? null : sectionsRecyclerView.getRecyclerView());
    }
  }

  public @Nullable RecyclerView getRecyclerView() {
    return mSectionsRecyclerView == null ? null : mSectionsRecyclerView.getRecyclerView();
  }

  public void setOnRecyclerUpdateListener(
      @Nullable OnRecyclerUpdateListener onRecyclerUpdateListener) {
    mOnRecyclerUpdateListener = onRecyclerUpdateListener;
  }
}

@@ -1350,30 +1350,106 @@
 %7B%0A          
-if (mS
+SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView;%0A          if (s
 ectionsRecyc
@@ -1467,18 +1467,17 @@
 null && 
-mS
+s
 ectionsR
@@ -1514,26 +1514,25 @@
             
-mS
+s
 ectionsRecyc
@@ -2164,38 +2164,108 @@
 animated) %7B%0A    
-if (mS
+SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView;%0A    if (s
 ectionsRecyclerV
@@ -2318,34 +2318,33 @@
 imated) %7B%0A      
-mS
+s
 ectionsRecyclerV
@@ -2416,34 +2416,33 @@
 urn;%0A    %7D%0A%0A    
-mS
+s
 ectionsRecyclerV
@@ -2526,32 +2526,103 @@
 reshing() %7B%0A
+    SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView;%0A
     if (
 mSectionsRec
@@ -2601,34 +2601,33 @@
 erView;%0A    if (
-mS
+s
 ectionsRecyclerV
@@ -2642,18 +2642,17 @@
 ull %7C%7C !
-mS
+s
 ectionsR
@@ -2742,26 +2742,25 @@
 ()) %7B%0A      
-mS
+s
 ectionsRecyc
@@ -2810,26 +2810,25 @@
 %0A    %7D%0A%0A    
-mS
+s
 ectionsRecyc
@@ -2875,26 +2875,25 @@
 nable);%0A    
-mS
+s
 ectionsRecyc
@@ -2975,14 +2975,84 @@
     
-if (mS
+SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView;%0A    if (s
 ecti
@@ -3078,18 +3078,17 @@
 null %7C%7C 
-mS
+s
 ectionsR
@@ -3173,26 +3173,25 @@
 read();%0A    
-mS
+s
 ectionsRecyc
@@ -3596,24 +3596,95 @@
 lerView() %7B%0A
+    SectionsRecyclerView sectionsRecyclerView = mSectionsRecyclerView;%0A
     return m
@@ -3682,18 +3682,17 @@
  return 
-mS
+s
 ectionsR
@@ -3720,18 +3720,17 @@
  null : 
-mS
+s
 ectionsR

Fix NPE in RecyclerEventsController