/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.weex.ui.component.list;

import android.view.View;
import android.view.ViewGroup;

import org.apache.weex.WXEnvironment;
import org.apache.weex.common.WXThread;
import org.apache.weex.utils.WXLogUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by sospartan on 17/03/2017.
 */

public class StickyHeaderHelper {
  private final ViewGroup mParent;
  private Map<String,View> mHeaderViews = new HashMap<>(); // map for <ref,view>
  private Map<String,WXCell> mHeaderComps = new HashMap<>(); // map for <ref,comp>
  private String mCurrentStickyRef = null;

  public StickyHeaderHelper(ViewGroup parent){
    this.mParent = parent;
  }

  /**
   * @param component
   */
  public void notifyStickyShow(WXCell component) {
    if (component == null)
      return;
    mHeaderComps.put(component.getRef(),component);
    if(mCurrentStickyRef != null){
      WXCell cell = mHeaderComps.get(mCurrentStickyRef);
      if(cell ==null || component.getScrollPositon() > cell.getScrollPositon()){
        mCurrentStickyRef = component.getRef();
      }
    }else{
      mCurrentStickyRef = component.getRef();
    }

    {
      if(mCurrentStickyRef==null){
        WXLogUtils.e("Current Sticky ref is null.");
        return;
      }

      WXCell headComponent = mHeaderComps.get(mCurrentStickyRef);
      final View headerView = headComponent.getRealView();
      if (headerView == null) {
        WXLogUtils.e("Sticky header's real view is null.");
        return;
      }
      View header = mHeaderViews.get(headComponent.getRef());
      if( header != null){
        //already there
        header.bringToFront();
      }else {
        mHeaderViews.put(headComponent.getRef(), headerView);
        //record translation, it should not change after transformation
        final float translationX = headerView.getTranslationX();
        final float translationY = headerView.getTranslationY();
        headComponent.removeSticky();

        ViewGroup existedParent;
        if ((existedParent = (ViewGroup) headerView.getParent()) != null) {
          existedParent.removeView(headerView);
        }
        headerView.setTag(headComponent.getRef());
        ViewGroup.MarginLayoutParams mlp =
                new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
        mParent.addView(headerView, mlp);
        headerView.setTag(this);
        if(headComponent.getStickyOffset() > 0) {
          ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) headerView.getLayoutParams();
          if(headComponent.getStickyOffset() != params.topMargin) {
            params.topMargin = headComponent.getStickyOffset();
          }
        }
        //recover translation, sometimes it will be changed on fling
        headerView.setTranslationX(translationX);
        headerView.setTranslationY(translationY);
      }
      changeFrontStickyVisible();
      if (headComponent.getEvents().contains("sticky")) {
        headComponent.fireEvent("sticky");
      }
    }
  }


  public void notifyStickyRemove(WXCell compToRemove) {
    if (compToRemove == null)
      return;
    final WXCell component = mHeaderComps.containsValue(compToRemove) ? mHeaderComps.remove(compToRemove.getRef()) : compToRemove;
    final View headerView = mHeaderViews.remove(compToRemove.getRef());

    if(component == null || headerView == null){
      if(WXEnvironment.isApkDebugable()) {
      }
      return;
    }
    if(mCurrentStickyRef != null && mCurrentStickyRef.equals(compToRemove.getRef())){
      mCurrentStickyRef = null;
    }
    mParent.post(WXThread.secure(new Runnable() {
      @Override
      public void run() {
        mParent.removeView(headerView);
        if(headerView.getVisibility() != View.VISIBLE){
          headerView.setVisibility(View.VISIBLE);
        }
        component.recoverySticky();
        changeFrontStickyVisible();

      }
    }));
    if (component.getEvents().contains("unsticky")) {
      component.fireEvent("unsticky");
    }
  }


  public void updateStickyView(int currentStickyPos) {
    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();
    List<WXCell> toRemove = new ArrayList<>();
    while(iterator.hasNext()){
      Map.Entry<String, WXCell> next = iterator.next();
      WXCell cell = next.getValue();
      int pos = cell.getScrollPositon();
      if(pos > currentStickyPos){
        toRemove.add(cell);
      }else if(pos == currentStickyPos){
        mCurrentStickyRef = cell.getRef();
        View view = mHeaderViews.get(cell.getRef());
        if(view != null){
          view.bringToFront();
          changeFrontStickyVisible();
        }
      }
    }
    for(WXCell cell:toRemove){
      notifyStickyRemove(cell);
    }
  }

  public void  clearStickyHeaders(){
    if(mHeaderViews.size() <= 0){
      return;
    }
    Iterator<Map.Entry<String, WXCell>> iterator = mHeaderComps.entrySet().iterator();

    while (iterator.hasNext()) {
      Map.Entry<String, WXCell> next = iterator.next();
      WXCell value = next.getValue();
      iterator.remove();
      notifyStickyRemove(value);
    }
  }


  private void changeFrontStickyVisible(){
    if(mHeaderViews.size() <= 0){
      return;
    }
    boolean  fontVisible = false;
    for(int i=mParent.getChildCount()-1; i>=0; i--){
      View view = mParent.getChildAt(i);
      if(fontVisible && view.getTag() instanceof  StickyHeaderHelper){
        if(view.getVisibility() != View.GONE){
          view.setVisibility(View.GONE);
        }
      }else{
        if(view.getTag() instanceof  StickyHeaderHelper){
          fontVisible = true;
          if(view != null && view.getVisibility() != View.VISIBLE){
            view.setVisibility(View.VISIBLE);
          }
        }
      }
    }
  }
}
